From a419fbe64441bed40c4a14ff9822beb71501d875 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 23 Nov 2021 08:49:53 +1030 Subject: [PATCH 001/121] Input: Refactor input type checks --- src/input.cpp | 83 +++++++++++++++++---------------------------------- src/input.h | 11 +++---- src/main.cpp | 8 ++--- 3 files changed, 36 insertions(+), 66 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index 57e1d626..2ae81cdb 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -258,7 +258,7 @@ uint16_t input_get_state(uint8_t id, void *response, bool *combo_pressed) if (response == NULL) return 0; - if (input_is_gamecontroller(id)) + if (input_is(id, USB_GAMECONTROLLER)) { //Prep N64 response n64_buttonmap *state = (n64_buttonmap *)response; @@ -481,7 +481,7 @@ uint16_t input_get_state(uint8_t id, void *response, bool *combo_pressed) } } #if (MAX_MICE >= 1) - else if (input_is_mouse(id)) + else if (input_is(id, USB_MOUSE)) { //Prep N64 response n64_buttonmap *state = (n64_buttonmap *)response; @@ -517,7 +517,7 @@ uint16_t input_get_state(uint8_t id, void *response, bool *combo_pressed) #endif #if (MAX_KB >= 1) - else if (input_is_kb(id)) + else if (input_is(id, USB_KB)) { //Prep N64 response n64_randnet_kb *state = (n64_randnet_kb *)response; @@ -560,7 +560,7 @@ uint16_t input_get_state(uint8_t id, void *response, bool *combo_pressed) #endif #if (ENABLE_HARDWIRED_CONTROLLER >=1) - else if (input_is_hw_gamecontroller(id)) + else if (input_is(id, HW_GAMECONTROLLER)) { n64_buttonmap *state = (n64_buttonmap *)response; state->dButtons = 0; @@ -599,13 +599,13 @@ uint16_t input_get_state(uint8_t id, void *response, bool *combo_pressed) void input_apply_rumble(int id, uint8_t strength) { JoystickController *joy; - if (input_is_gamecontroller(id)) + if (input_is(id, USB_GAMECONTROLLER)) { joy = (JoystickController *)input_devices[id].driver; joy->setRumble(strength, strength, 20); } #if (ENABLE_HARDWIRED_CONTROLLER >=1) - else if (input_is_hw_gamecontroller(id)) + else if (input_is(id, HW_GAMECONTROLLER)) { (strength > 0) ? digitalWrite(HW_RUMBLE, HIGH) : digitalWrite(HW_RUMBLE, LOW); } @@ -618,7 +618,7 @@ bool input_is_connected(int id) if (_check_id(id) == 0) return false; - if (input_is_gamecontroller(id)) + if (input_is(id, USB_GAMECONTROLLER)) { JoystickController *joy = (JoystickController *)input_devices[id].driver; if (*joy == true) @@ -626,7 +626,7 @@ bool input_is_connected(int id) } #if (MAX_MICE >=1) - else if (input_is_mouse(id)) + else if (input_is(id, USB_MOUSE)) { USBHIDInput *mouse = (USBHIDInput *)input_devices[id].driver; if (*mouse == true) @@ -635,7 +635,7 @@ bool input_is_connected(int id) #endif #if (MAX_KB >=1) - else if (input_is_kb(id)) + else if (input_is(id, USB_KB)) { USBHIDInput *kb = (USBHIDInput *)input_devices[id].driver; if (*kb == true) @@ -644,7 +644,7 @@ bool input_is_connected(int id) #endif #if (ENABLE_HARDWIRED_CONTROLLER >=1) - else if (input_is_hw_gamecontroller(id)) + else if (input_is(id, HW_GAMECONTROLLER)) { if (digitalRead(HW_EN) == 0) connected = true; @@ -654,38 +654,11 @@ bool input_is_connected(int id) return connected; } -bool input_is_mouse(int id) +bool input_is(int id, input_type_t type) { if (_check_id(id) == 0) return false; - if (input_devices[id].type == USB_MOUSE) - return true; - return false; -} - -bool input_is_kb(int id) -{ - if (_check_id(id) == 0) - return false; - if (input_devices[id].type == USB_KB) - return true; - return false; -} - -bool input_is_gamecontroller(int id) -{ - if (_check_id(id) == 0) - return false; - if (input_devices[id].type == USB_GAMECONTROLLER) - return true; - return false; -} - -bool input_is_hw_gamecontroller(int id) -{ - if (_check_id(id) == 0) - return false; - if (input_devices[id].type == HW_GAMECONTROLLER) + if (input_devices[id].type == type) return true; return false; } @@ -695,22 +668,22 @@ uint16_t input_get_id_product(int id) if (_check_id(id) == 0 || input_is_connected(id) == 0) return 0; - if (input_is_gamecontroller(id)) + if (input_is(id, USB_GAMECONTROLLER)) { JoystickController *joy = (JoystickController *)input_devices[id].driver; return joy->idProduct(); } - else if (input_is_mouse(id)) + else if (input_is(id, USB_MOUSE)) { USBHIDInput *mouse = (USBHIDInput *)input_devices[id].driver; return mouse->idProduct(); } - else if (input_is_kb(id)) + else if (input_is(id, USB_KB)) { USBHIDInput *kb = (USBHIDInput *)input_devices[id].driver; return kb->idProduct(); } - else if (input_is_hw_gamecontroller(id)) + else if (input_is(id, HW_GAMECONTROLLER)) { return 0xBEEF; } @@ -723,22 +696,22 @@ uint16_t input_get_id_vendor(int id) if (_check_id(id) == 0 || input_is_connected(id) == 0) return 0; - if (input_is_gamecontroller(id)) + if (input_is(id, USB_GAMECONTROLLER)) { JoystickController *joy = (JoystickController *)input_devices[id].driver; return joy->idVendor(); } - else if (input_is_mouse(id)) + else if (input_is(id, USB_MOUSE)) { USBHIDInput *mouse = (USBHIDInput *)input_devices[id].driver; return mouse->idVendor(); } - else if (input_is_kb(id)) + else if (input_is(id, USB_KB)) { USBHIDInput *kb = (USBHIDInput *)input_devices[id].driver; return kb->idVendor(); } - else if (input_is_hw_gamecontroller(id)) + else if (input_is(id, HW_GAMECONTROLLER)) { return 0xDEAD; } @@ -752,22 +725,22 @@ const char *input_get_manufacturer_string(int id) if (_check_id(id) == 0 || input_is_connected(id) == false) return NC; - if (input_is_gamecontroller(id)) + if (input_is(id, USB_GAMECONTROLLER)) { JoystickController *joy = (JoystickController *)input_devices[id].driver; return (const char *)joy->manufacturer(); } - else if (input_is_mouse(id)) + else if (input_is(id, USB_MOUSE)) { USBHIDInput *mouse = (USBHIDInput *)input_devices[id].driver; return (const char *)mouse->manufacturer(); } - else if (input_is_kb(id)) + else if (input_is(id, USB_KB)) { USBHIDInput *kb = (USBHIDInput *)input_devices[id].driver; return (const char *)kb->manufacturer(); } - else if (input_is_hw_gamecontroller(id)) + else if (input_is(id, HW_GAMECONTROLLER)) { return "USB64"; } @@ -781,22 +754,22 @@ const char *input_get_product_string(int id) if (_check_id(id) == 0 || input_is_connected(id) == 0) return NC; - if (input_is_gamecontroller(id)) + if (input_is(id, USB_GAMECONTROLLER)) { JoystickController *joy = (JoystickController *)input_devices[id].driver; return (const char *)joy->product(); } - else if (input_is_mouse(id)) + else if (input_is(id, USB_MOUSE)) { USBHIDInput *mouse = (USBHIDInput *)input_devices[id].driver; return (const char *)mouse->product(); } - else if (input_is_kb(id)) + else if (input_is(id, USB_KB)) { USBHIDInput *kb = (USBHIDInput *)input_devices[id].driver; return (const char *)kb->product(); } - else if (input_is_hw_gamecontroller(id)) + else if (input_is(id, HW_GAMECONTROLLER)) { return "HARDWIRED"; } diff --git a/src/input.h b/src/input.h index 7806e1d7..a003df90 100644 --- a/src/input.h +++ b/src/input.h @@ -99,28 +99,25 @@ static const randnet_map_t randnet_map[] = { {KEY_RIGHT, 0x0405}, //Right Cursor }; -enum +typedef enum { USB_MOUSE, USB_KB, USB_GAMECONTROLLER, HW_GAMECONTROLLER, I2C_GAMECONTROLLER -}; +} input_type_t; typedef struct { void *driver; - int type; + input_type_t type; } input; void input_init(); void input_update_input_devices(); bool input_is_connected(int id); -bool input_is_mouse(int id); -bool input_is_kb(int id); -bool input_is_gamecontroller(int id); -bool input_is_hw_gamecontroller(int id); +bool input_is(int id, input_type_t type); uint16_t input_get_id_product(int id); uint16_t input_get_id_vendor(int id); const char *input_get_manufacturer_string(int id); diff --git a/src/main.cpp b/src/main.cpp index bd17e05c..5c533a78 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -151,7 +151,7 @@ void loop() } n64_in_dev[c].interrupt_attached = true; } - if (input_is_gamecontroller(c)) + if (input_is(c, USB_GAMECONTROLLER)) { n64_buttonmap *new_state = (n64_buttonmap *)n64_response[c]; input_get_state(c, new_state, &n64_combo); @@ -191,7 +191,7 @@ void loop() } } #if (MAX_MICE >= 1) - else if (input_is_mouse(c)) + else if (input_is(c, USB_MOUSE)) { n64_buttonmap *new_state = (n64_buttonmap *)n64_response[c]; input_get_state(c, new_state, &n64_combo); @@ -207,7 +207,7 @@ void loop() } #endif #if (MAX_KB >= 1) - else if (input_is_kb(c)) + else if (input_is(c, USB_KB)) { n64_randnet_kb *new_state = (n64_randnet_kb *)n64_response[c]; //Maintain the old led state @@ -233,7 +233,7 @@ void loop() //Get a copy of the latest n64 button presses to handle the below combos uint16_t n64_buttons = 0; - if (input_is_gamecontroller(c)) + if (input_is(c, USB_GAMECONTROLLER)) { n64_buttonmap *new_state = (n64_buttonmap *)n64_response[c]; n64_buttons = new_state->dButtons; From c9612837e3df85be83dfc9ebb096b84b12e6f1f7 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 23 Nov 2021 10:12:27 +1030 Subject: [PATCH 002/121] FileIO: Rework for portability --- platformio.ini | 2 + src/fileio.cpp | 62 +++++++++++++-------------- src/fileio.h | 10 +++-- src/teensy41/fileio_t4.cpp | 85 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 37 deletions(-) create mode 100644 src/teensy41/fileio_t4.cpp diff --git a/platformio.ini b/platformio.ini index 965f8bbb..4ac8ac47 100644 --- a/platformio.ini +++ b/platformio.ini @@ -60,6 +60,8 @@ src_filter = + + + + + + + + build_flags = diff --git a/src/fileio.cpp b/src/fileio.cpp index 19e0ac9f..97bf921d 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -1,20 +1,21 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include -#include +#include +#include #include "usb64_conf.h" #include "printf.h" +#include "fileio.h" void fileio_init() { - if (!SD.sdfs.begin(SdioConfig(FIFO_SDIO))) + if (!fileio_dev_init()) { debug_print_error("[FILEIO] ERROR: Could not open SD Card\n"); } else { - debug_print_fatfs("[FILEIO] Opened SD card OK! Size: %lld MB\n", SD.totalSize()/1024/1024); + debug_print_fatfs("[FILEIO] Opened SD card OK!\n"); } } @@ -31,30 +32,31 @@ void fileio_init() uint32_t fileio_list_directory(char **list, uint32_t max) { int file_count = 0; - File root = SD.open("/"); + int root = fileio_dev_open_dir("/"); - if (root == false) + if (root == 0) { debug_print_error("[FILEIO] ERROR: Could not read SD Card\n"); return 0; } + debug_print_fatfs("[FILEIO] fileio_list_directory %08x!\n", root); + while (true) { - File entry = root.openNextFile(); - if (entry == false) - break; + const char* filename = fileio_dev_get_next_filename(root); - if (!entry.isDirectory()) + if (filename == NULL) { - debug_print_fatfs("Found file: %s\n", entry.name()); - list[file_count] = (char *)malloc(strlen(entry.name()) + 1); - strcpy(list[file_count], entry.name()); - file_count++; + break; } - entry.close(); + + debug_print_fatfs("Found file: %s\n", filename); + list[file_count] = (char *)malloc(strlen(filename) + 1); + strcpy(list[file_count], filename); + file_count++; } - root.close(); + fileio_dev_close_dir(root); return file_count; } @@ -69,21 +71,19 @@ uint32_t fileio_list_directory(char **list, uint32_t max) */ void fileio_write_to_file(char *filename, uint8_t *data, uint32_t len) { - FsFile fil = SD.sdfs.open(filename, O_WRITE | O_CREAT); - if (fil == false) + int ret = fileio_dev_write(filename, data, len); + if (ret == -1) { debug_print_error("[FILEIO] ERROR: Could not open %s for WRITE\n", filename); - return; } - if (fil.write(data, len) != len) + else if (ret == -2) { debug_print_error("[FILEIO] ERROR: Could not write %s\n", filename); } - else + else if (ret == -3) { - debug_print_status("[FILEIO] Writing %s for %u bytes ok!\n", filename, len); + debug_print_status("[FILEIO] Writing %s for %lu bytes ok!\n", filename, len); } - fil.close(); } /* @@ -99,22 +99,18 @@ void fileio_write_to_file(char *filename, uint8_t *data, uint32_t len) */ void fileio_read_from_file(char *filename, uint32_t file_offset, uint8_t *data, uint32_t len) { - FsFile fil = SD.sdfs.open(filename, O_READ); - if (fil == false) + int ret = fileio_dev_read(filename, file_offset, data, len); + + if (ret == -1) { debug_print_error("[FILEIO] ERROR: Could not open %s for READ\n", filename); - return; } - - fil.seekSet(file_offset); - - if (fil.read(data, len) != (int)len) + else if (ret == -2) { debug_print_error("[FILEIO] ERROR: Could not read %s\n", filename); } - else + else if (ret == -3) { - debug_print_status("[FILEIO] Reading %s for %u bytes ok!\n", filename, len); + debug_print_status("[FILEIO] Reading %s for %lu bytes ok!\n", filename, len); } - fil.close(); } diff --git a/src/fileio.h b/src/fileio.h index 1dedebf8..5f33ca37 100644 --- a/src/fileio.h +++ b/src/fileio.h @@ -4,7 +4,6 @@ #ifndef _FILEIO_H #define _FILEIO_H -#include #include "usb64_conf.h" void fileio_init(void); @@ -12,8 +11,11 @@ void fileio_write_to_file(char *filename, uint8_t *data, uint32_t len); void fileio_read_from_file(char *filename, uint32_t file_offset, uint8_t *data, uint32_t len); uint32_t fileio_list_directory(char **list, uint32_t max); -int fileio_open_file_readonly(const char *filename); -void fileio_close_file(); -int fileio_get_line(char* buffer, int max_len); +bool fileio_dev_init(); +int fileio_dev_open_dir(const char* dir); +void fileio_dev_close_dir(int handle); +const char* fileio_dev_get_next_filename(int handle); +int fileio_dev_read(char *filename, uint32_t file_offset, uint8_t *data, uint32_t len); +int fileio_dev_write(char *filename, uint8_t *data, uint32_t len); #endif diff --git a/src/teensy41/fileio_t4.cpp b/src/teensy41/fileio_t4.cpp new file mode 100644 index 00000000..914274f7 --- /dev/null +++ b/src/teensy41/fileio_t4.cpp @@ -0,0 +1,85 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include + +bool fileio_dev_init() +{ + return SD.sdfs.begin(SdioConfig(FIFO_SDIO)); +} + +int fileio_dev_open_dir(const char* dir) +{ + File *handle = new File(); + *handle = SD.open("/"); + if (*handle == false) + { + return 0; + } + else + { + return (int)handle; + } +} + +const char *fileio_dev_get_next_filename(int handle) +{ + File *_handle = (File *)handle; + const char *filename = NULL; + File entry = _handle->openNextFile(); + + if (entry == false) + { + return NULL; + } + filename = entry.name(); + entry.close(); + return filename; +} + +void fileio_dev_close_dir(int handle) +{ + File *_handle = (File *)handle; + _handle->close(); + delete _handle; +} + +int fileio_dev_read(char *filename, uint32_t file_offset, uint8_t *data, uint32_t len) +{ + FsFile fil = SD.sdfs.open(filename, O_READ); + if (fil == false) + { + return -1; + } + + fil.seekSet(file_offset); + + if (fil.read(data, len) != (int)len) + { + return -2; + } + else + { + return -3; + } + fil.close(); +} + +int fileio_dev_write(char *filename, uint8_t *data, uint32_t len) +{ + FsFile fil = SD.sdfs.open(filename, O_WRITE | O_CREAT); + if (fil == false) + { + return -1; + } + if (fil.write(data, len) != len) + { + return -2; + } + else + { + return -3; + } + fil.close(); +} From 75415cf00115a70effa963915ad00fc1ad0ab138 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 23 Nov 2021 10:49:18 +1030 Subject: [PATCH 003/121] Memory: Rework for portability --- src/fileio.cpp | 3 +- src/memory.cpp | 47 ++++++++--------------------- src/memory.h | 5 ++- src/n64_wrapper.cpp | 5 +-- src/teensy41/memory_t4.cpp | 62 ++++++++++++++++++++++++++++++++++++++ src/tft/tft.cpp | 4 +-- 6 files changed, 85 insertions(+), 41 deletions(-) create mode 100644 src/teensy41/memory_t4.cpp diff --git a/src/fileio.cpp b/src/fileio.cpp index 97bf921d..d593a49e 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -6,6 +6,7 @@ #include "usb64_conf.h" #include "printf.h" #include "fileio.h" +#include "memory.h" void fileio_init() { @@ -52,7 +53,7 @@ uint32_t fileio_list_directory(char **list, uint32_t max) } debug_print_fatfs("Found file: %s\n", filename); - list[file_count] = (char *)malloc(strlen(filename) + 1); + list[file_count] = (char *)memory_dev_malloc(strlen(filename) + 1); strcpy(list[file_count], filename); file_count++; } diff --git a/src/memory.cpp b/src/memory.cpp index 29eb43dd..701121fd 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -17,20 +17,18 @@ #include "fileio.h" #include "printf.h" -extern uint8_t external_psram_size; //in MB. Set in startup.c -EXTMEM uint8_t ext_ram[1]; //Just to get the start of EXTMEM -static uint32_t internal_size = 32768; //Smaller than this will malloc to internal RAM instead static sram_storage sram[32] = {0}; void memory_init() { - if (external_psram_size == 0) - return; - - debug_print_memory("[MEMORY] External memory initialised\n"); - debug_print_memory("[MEMORY] Detected %uMB\n", external_psram_size); - debug_print_memory("[MEMORY] Heap start: %08x\n", (uint32_t)ext_ram); - debug_print_memory("[MEMORY] Heap end: %08x\n", (uint32_t)ext_ram + external_psram_size * 1024 * 1024); + if (!memory_dev_init()) + { + debug_print_memory("[MEMORY] Warning: External memory not initialised\n"); + } + else + { + debug_print_memory("[MEMORY] External memory initialised\n"); + } } //This function allocates and manages SRAM for mempak and gameboy roms (tpak) for the system. @@ -58,13 +56,7 @@ uint8_t *memory_alloc_ram(const char *name, uint32_t alloc_len, uint32_t read_on debug_print_error("[MEMORY] ERROR: SRAM malloced memory isnt right, resetting memory\n"); //Allocated length isnt long enough. Reset it to be memory safe - if(sram[i].data != NULL) - { - if (sram[i].data >= ext_ram) - extmem_free(sram[i].data); - else - free(sram[i].data); - } + memory_dev_free(sram[i].data); sram[i].data = NULL; sram[i].len = 0; } @@ -74,16 +66,9 @@ uint8_t *memory_alloc_ram(const char *name, uint32_t alloc_len, uint32_t read_on { if (sram[i].len == 0) { - //Smaller blocks are RAM are mallocs internally for better performance. Teensy has a reasonable - //amount of internal RAM :) - (alloc_len <= internal_size || external_psram_size == 0) ? (sram[i].data = (uint8_t *)malloc(alloc_len)) : - (sram[i].data = (uint8_t *)extmem_malloc(alloc_len)); - - //If failed to malloc to internal RAM, try external RAM - if (sram[i].data == NULL && alloc_len <= internal_size && external_psram_size > 0) - sram[i].data = (uint8_t *)extmem_malloc(alloc_len); + sram[i].data = (uint8_t *)memory_dev_malloc(alloc_len); - //If it still failed, no RAM left? + //If failed, no RAM left? if (sram[i].data == NULL) break; @@ -116,10 +101,7 @@ void memory_free_item(void *ptr) if (sram[i].data == ptr) { debug_print_memory("[MEMORY] Freeing %s at 0x%08x\n", sram[i].name, sram[i].data); - if (sram[i].data >= ext_ram) - extmem_free(sram[i].data); - else - free(sram[i].data); + memory_dev_free(sram[i].data); sram[i].name[0] = '\0'; sram[i].data = NULL; sram[i].len = 0; @@ -162,8 +144,3 @@ void memory_mark_dirty(void *ptr) } debug_print_error("[MEMORY] ERROR: Could not find 0x%08x\n", ptr); } - -uint8_t memory_get_ext_ram_size() -{ - return external_psram_size; -} \ No newline at end of file diff --git a/src/memory.h b/src/memory.h index 55efb9a5..63071d8f 100644 --- a/src/memory.h +++ b/src/memory.h @@ -4,7 +4,6 @@ #ifndef _MEMORY_H #define _MEMORY_H -#include #include "usb64_conf.h" #define MEMORY_READ_WRITE 0 @@ -26,4 +25,8 @@ void memory_free_item(void *ptr); void memory_mark_dirty(void *ptr); uint8_t memory_get_ext_ram_size(); +bool memory_dev_init(); +void *memory_dev_malloc(uint32_t len); +void memory_dev_free(void *add); + #endif diff --git a/src/n64_wrapper.cpp b/src/n64_wrapper.cpp index ae901b7d..c6d48f43 100644 --- a/src/n64_wrapper.cpp +++ b/src/n64_wrapper.cpp @@ -7,6 +7,7 @@ #include "memory.h" #include "usb64_conf.h" #include "fileio.h" +#include "memory.h" /* * Function: Reads a hardware realtime clock and populates day,h,m,s. @@ -189,13 +190,13 @@ uint32_t n64hal_list_gb_roms(char **gb_list, uint32_t max) { if (rom_count < max) { - gb_list[rom_count] = (char *)malloc(strlen(file_list[i]) + 1); + gb_list[rom_count] = (char *)memory_dev_malloc(strlen(file_list[i]) + 1); strcpy(gb_list[rom_count], file_list[i]); rom_count++; } } //Free file list as we go - free(file_list[i]); + memory_dev_free(file_list[i]); } return rom_count; } diff --git a/src/teensy41/memory_t4.cpp b/src/teensy41/memory_t4.cpp new file mode 100644 index 00000000..9e25e3d1 --- /dev/null +++ b/src/teensy41/memory_t4.cpp @@ -0,0 +1,62 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include "memory.h" +#include "printf.h" + +static uint32_t internal_size = 32768; //Smaller than this will malloc to internal RAM instead +extern uint8_t external_psram_size; //in MB. Set in startup.c +EXTMEM uint8_t ext_ram[1]; //Just to get the start of EXTMEM + +bool memory_dev_init() +{ + if (external_psram_size == 0) + return false; + + debug_print_memory("[MEMORY] Detected %uMB\n", external_psram_size); + debug_print_memory("[MEMORY] Heap start: %08x\n", (uint32_t)ext_ram); + debug_print_memory("[MEMORY] Heap end: %08x\n", (uint32_t)ext_ram + external_psram_size * 1024 * 1024); + return true; +} + +void *memory_dev_malloc(uint32_t len) +{ + void *add = NULL; + + //Try internal RAM for smaller files for best performance + if (len <= internal_size || external_psram_size == 0) + { + add = malloc(len); + } + + //If failed to malloc to internal RAM, try external RAM + if (add == NULL) + { + add = (uint8_t *)extmem_malloc(len); + } + + return add; +} + +void memory_dev_free(void *add) +{ + if (add == NULL) + { + return; + } + //If the address range is in the external RAM memory map, call the correct free function. + if (add >= ext_ram) + { + extmem_free(add); + } + else + { + free(add); + } +} + +uint8_t memory_get_ext_ram_size() +{ + return external_psram_size; +} diff --git a/src/tft/tft.cpp b/src/tft/tft.cpp index 97d3227c..adab410e 100644 --- a/src/tft/tft.cpp +++ b/src/tft/tft.cpp @@ -300,7 +300,7 @@ void tft_add_log(char c) if (c == '\n') { tft_log[tft_log_pos] = '\0'; - _tft_log_text_lines[tft_log_line_num] = (char *)malloc(strlen(tft_log) + 1); + _tft_log_text_lines[tft_log_line_num] = (char *)memory_dev_malloc(strlen(tft_log) + 1); strcpy(_tft_log_text_lines[tft_log_line_num], tft_log); tft_log_line_num++; tft_log_pos = 0; @@ -310,7 +310,7 @@ void tft_add_log(char c) //Exceeded max lines, remove oldest line and shift lines up by one if (tft_log_line_num >= _tft_log_max_lines) { - free(_tft_log_text_lines[0]); + memory_dev_free(_tft_log_text_lines[0]); for (uint32_t i = 0; i < _tft_log_max_lines - 1; i++) { _tft_log_text_lines[i] = _tft_log_text_lines[i + 1]; From 14f7159188dace11443fe36b21da25a958cea79e Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 23 Nov 2021 11:14:43 +1030 Subject: [PATCH 004/121] T4: Move HAL wrapper to Teensy folder --- src/n64_wrapper.h | 1 - src/{n64_wrapper.cpp => teensy41/hal_t4.cpp} | 0 2 files changed, 1 deletion(-) rename src/{n64_wrapper.cpp => teensy41/hal_t4.cpp} (100%) diff --git a/src/n64_wrapper.h b/src/n64_wrapper.h index 9f1afd90..59c90920 100644 --- a/src/n64_wrapper.h +++ b/src/n64_wrapper.h @@ -8,7 +8,6 @@ extern "C" { #endif -#include #include "n64_controller.h" #define N64_OUTPUT 1 diff --git a/src/n64_wrapper.cpp b/src/teensy41/hal_t4.cpp similarity index 100% rename from src/n64_wrapper.cpp rename to src/teensy41/hal_t4.cpp From dd6a03c77b50ca10f5a277174212ef7963df1181 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 23 Nov 2021 12:11:22 +1030 Subject: [PATCH 005/121] Main: Rework for portability --- src/main.cpp | 100 +++++++++++++++++++++++----------------- src/n64_wrapper.h | 14 ++++++ src/teensy41/hal_t4.cpp | 60 ++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 42 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 5c533a78..674ad557 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,8 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include #include "input.h" #include "printf.h" -#include "n64_wrapper.h" #include "usb64_conf.h" #include "n64_controller.h" #include "n64_transferpak_gbcarts.h" @@ -14,7 +12,7 @@ #include "memory.h" #include "fileio.h" #include "tft.h" - +#include "n64_wrapper.h" static void ring_buffer_init(void); static void ring_buffer_flush(); @@ -48,22 +46,43 @@ void n64_controller4_clock_edge() } #endif +#ifdef __IMXRT1062__ extern "C" { FLASHMEM void startup_early_hook(void) { //Get these up as early as possible. - pinMode(N64_CONTROLLER_1_PIN, INPUT_PULLUP); - pinMode(N64_CONTROLLER_2_PIN, INPUT_PULLUP); - pinMode(N64_CONTROLLER_3_PIN, INPUT_PULLUP); - pinMode(N64_CONTROLLER_4_PIN, INPUT_PULLUP); - pinMode(N64_CONSOLE_SENSE, INPUT_PULLDOWN); + n64hal_pin_set_mode(N64_CONTROLLER_1_PIN, N64_INPUT_PULLUP); + n64hal_pin_set_mode(N64_CONTROLLER_2_PIN, N64_INPUT_PULLUP); + n64hal_pin_set_mode(N64_CONTROLLER_3_PIN, N64_INPUT_PULLUP); + n64hal_pin_set_mode(N64_CONTROLLER_4_PIN, N64_INPUT_PULLUP); + n64hal_pin_set_mode(N64_CONSOLE_SENSE, N64_INPUT_PULLDOWN); } } +#else +void startup_early_hook(void) +{ + +} +#endif + +#ifndef ARDUINO +#include +#include +#include +#include +int main() +{ + startup_early_hook(); + setup(); + loop(); +} +#endif void setup() { //Init the serial port and ring buffer - serial_port.begin(256000); + n64hal_system_init(); + n64hal_debug_init(); ring_buffer_init(); fileio_init(); memory_init(); @@ -77,52 +96,49 @@ void setup() //Set up N64 sense pin. To determine is the N64 is turned on or off //Input is connected to the N64 3V3 line on the controller port. - pinMode(N64_CONSOLE_SENSE, INPUT_PULLDOWN); - - pinMode(N64_FRAME, OUTPUT); - - pinMode(USER_LED_PIN, OUTPUT); + n64hal_pin_set_mode(N64_CONSOLE_SENSE, N64_INPUT_PULLDOWN); + n64hal_pin_set_mode(N64_FRAME, N64_OUTPUT); + n64hal_pin_set_mode(USER_LED_PIN, N64_OUTPUT); #if (ENABLE_HARDWIRED_CONTROLLER >=1) - pinMode(HW_A, INPUT_PULLUP); - pinMode(HW_B, INPUT_PULLUP); - pinMode(HW_CU, INPUT_PULLUP); - pinMode(HW_CD, INPUT_PULLUP); - pinMode(HW_CL, INPUT_PULLUP); - pinMode(HW_CR, INPUT_PULLUP); - pinMode(HW_DU, INPUT_PULLUP); - pinMode(HW_DD, INPUT_PULLUP); - pinMode(HW_DL, INPUT_PULLUP); - pinMode(HW_DR, INPUT_PULLUP); - pinMode(HW_START, INPUT_PULLUP); - pinMode(HW_Z, INPUT_PULLUP); - pinMode(HW_R, INPUT_PULLUP); - pinMode(HW_L, INPUT_PULLUP); - pinMode(HW_EN, INPUT_PULLUP); - pinMode(HW_RUMBLE, OUTPUT); + n64hal_pin_set_mode(HW_A, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_B, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_CU, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_CD, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_CL, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_CR, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_DU, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_DD, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_DL, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_DR, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_START, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_Z, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_R, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_L, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_EN, N64_INPUT_PULLUP); + n64hal_pin_set_mode(HW_RUMBLE, N64_OUTPUT); #endif #if (MAX_CONTROLLERS >= 1) n64_in_dev[0].gpio_pin = N64_CONTROLLER_1_PIN; - pinMode(N64_CONTROLLER_1_PIN, INPUT_PULLUP); + n64hal_pin_set_mode(N64_CONTROLLER_1_PIN, N64_INPUT_PULLUP); #endif #if (MAX_CONTROLLERS >= 2) n64_in_dev[1].gpio_pin = N64_CONTROLLER_2_PIN; - pinMode(N64_CONTROLLER_2_PIN, INPUT_PULLUP); + n64hal_pin_set_mode(N64_CONTROLLER_2_PIN, N64_INPUT_PULLUP); #endif #if (MAX_CONTROLLERS >= 3) n64_in_dev[2].gpio_pin = N64_CONTROLLER_3_PIN; - pinMode(N64_CONTROLLER_3_PIN, INPUT_PULLUP); + n64hal_pin_set_mode(N64_CONTROLLER_3_PIN, N64_INPUT_PULLUP); #endif #if (MAX_CONTROLLERS >= 4) n64_in_dev[3].gpio_pin = N64_CONTROLLER_4_PIN; - pinMode(N64_CONTROLLER_4_PIN, INPUT_PULLUP); + n64hal_pin_set_mode(N64_CONTROLLER_4_PIN, N64_INPUT_PULLUP); #endif - NVIC_SET_PRIORITY(IRQ_GPIO6789, 1); - digitalWrite(USER_LED_PIN, HIGH); + n64hal_output_set(USER_LED_PIN, 1); } static bool n64_combo = false; @@ -144,10 +160,10 @@ void loop() { switch (c) { - case 0: attachInterrupt(digitalPinToInterrupt(n64_in_dev[c].gpio_pin), n64_controller1_clock_edge, FALLING); break; - case 1: attachInterrupt(digitalPinToInterrupt(n64_in_dev[c].gpio_pin), n64_controller2_clock_edge, FALLING); break; - case 2: attachInterrupt(digitalPinToInterrupt(n64_in_dev[c].gpio_pin), n64_controller3_clock_edge, FALLING); break; - case 3: attachInterrupt(digitalPinToInterrupt(n64_in_dev[c].gpio_pin), n64_controller4_clock_edge, FALLING); break; + case 0: n64hal_attach_interrupt(n64_in_dev[c].gpio_pin, n64_controller1_clock_edge, N64_INTMODE_FALLING); break; + case 1: n64hal_attach_interrupt(n64_in_dev[c].gpio_pin, n64_controller2_clock_edge, N64_INTMODE_FALLING); break; + case 2: n64hal_attach_interrupt(n64_in_dev[c].gpio_pin, n64_controller3_clock_edge, N64_INTMODE_FALLING); break; + case 3: n64hal_attach_interrupt(n64_in_dev[c].gpio_pin, n64_controller4_clock_edge, N64_INTMODE_FALLING); break; } n64_in_dev[c].interrupt_attached = true; } @@ -228,7 +244,7 @@ void loop() if ((!input_is_connected(c) || !n64_is_on) && n64_in_dev[c].interrupt_attached) { n64_in_dev[c].interrupt_attached = false; - detachInterrupt(digitalPinToInterrupt(n64_in_dev[c].gpio_pin)); + n64hal_detach_interrupt(n64_in_dev[c].gpio_pin); } //Get a copy of the latest n64 button presses to handle the below combos @@ -525,7 +541,7 @@ static void ring_buffer_flush() static uint32_t _print_cursor = 0; while (ring_buffer[_print_cursor] != 0xFF) { - serial_port.write(ring_buffer[_print_cursor]); + n64hal_debug_write(ring_buffer[_print_cursor]); ring_buffer[_print_cursor] = 0xFF; _print_cursor = (_print_cursor + 1) % sizeof(ring_buffer); } diff --git a/src/n64_wrapper.h b/src/n64_wrapper.h index 59c90920..fbf9362b 100644 --- a/src/n64_wrapper.h +++ b/src/n64_wrapper.h @@ -12,6 +12,19 @@ extern "C" { #define N64_OUTPUT 1 #define N64_INPUT 2 +#define N64_INPUT_PULLUP 2 +#define N64_INPUT_PULLDOWN 3 + +#define N64_INTMODE_FALLING 1 +#define N64_INTMODE_CHANGE 2 +#define N64_INTMODE_RISING 3 + +//System wrappers +void n64hal_system_init(); +void n64hal_debug_init(); +void n64hal_debug_write(char c); +void n64hal_attach_interrupt(uint8_t pin, void (*handler)(void), int mode); +void n64hal_detach_interrupt(uint8_t pin); //RTC wrapper prototypes (For gameboy roms with RTC, i.e Pokemon games) void n64hal_rtc_read(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s); @@ -30,6 +43,7 @@ void n64hal_write_extram(void *tx_buff, void *dst, uint32_t offset, uint32_t len void n64hal_output_set(uint8_t pin, uint8_t level); void n64hal_input_swap(n64_input_dev_t *controller, uint8_t val); uint8_t n64hal_input_read(n64_input_dev_t *controller); +void n64hal_pin_set_mode(int pin, uint8_t mode); //FileIO wrappers uint32_t n64hal_list_gb_roms(char **list, uint32_t max); diff --git a/src/teensy41/hal_t4.cpp b/src/teensy41/hal_t4.cpp index c6d48f43..84cd9674 100644 --- a/src/teensy41/hal_t4.cpp +++ b/src/teensy41/hal_t4.cpp @@ -9,6 +9,21 @@ #include "fileio.h" #include "memory.h" +void n64hal_system_init() +{ + NVIC_SET_PRIORITY(IRQ_GPIO6789, 1); +} + +void n64hal_debug_init() +{ + serial_port.begin(256000); +} + +void n64hal_debug_write(char c) +{ + serial_port.write(c); +} + /* * Function: Reads a hardware realtime clock and populates day,h,m,s. * Used by Pokemon Gameboy games only with TPAK that have a RTC. @@ -118,6 +133,31 @@ uint8_t n64hal_input_read(n64_input_dev_t *controller) return digitalReadFast(controller->gpio_pin); } +/* + * Function: Sets the GPIO mode of a pin + * ---------------------------- + * Returns: void + * + * Pin number (See usb64_conf.h) + * val: N64_OUTPUT or N64_INPUT_PULLDOWN or N64_INPUT_PULLUP + */ +void n64hal_pin_set_mode(int pin, uint8_t mode) +{ + switch (mode) + { + case N64_OUTPUT: + pinMode(pin, OUTPUT); + break; + case N64_INPUT_PULLDOWN: + pinMode(pin, INPUT_PULLDOWN); + break; + case N64_INPUT_PULLUP: + default: + pinMode(pin, INPUT_PULLUP); + break; + } +} + /* * Function: Sets an output GPI to a level * Speed critical! @@ -132,6 +172,26 @@ void n64hal_output_set(uint8_t pin, uint8_t level) digitalWriteFast(pin, level); } +void n64hal_attach_interrupt(uint8_t pin, void (*handler)(void), int mode) +{ + int _mode = -1; + switch (mode) + { + case N64_INTMODE_CHANGE: _mode = CHANGE; break; + case N64_INTMODE_FALLING: _mode = FALLING; break; + case N64_INTMODE_RISING: _mode = RISING; break; + } + if (_mode != -1) + { + attachInterrupt(digitalPinToInterrupt(pin), handler, _mode); + } +} + +void n64hal_detach_interrupt(uint8_t pin) +{ + detachInterrupt(digitalPinToInterrupt(pin)); +} + /* * Function: Returns an array of data read from external ram. * ---------------------------- From ab96e7ed6daeb2f15cff25fa9def5dc4007e239a Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 24 Nov 2021 19:15:33 +1030 Subject: [PATCH 006/121] TFT: Rework for portability. Implement GuiLite --- platformio.ini | 1 + src/lib/GuiLite.h | 4337 +++++++++++++++++++++++++++++++++++++++ src/teensy41/tft_t4.cpp | 86 + src/tft/Arial_14.cpp | 268 +++ src/tft/Arial_19.cpp | 268 +++ src/tft/tft.cpp | 329 ++- src/tft/tft.h | 13 +- src/usb64_conf.h | 2 + 8 files changed, 5129 insertions(+), 175 deletions(-) create mode 100644 src/lib/GuiLite.h create mode 100644 src/teensy41/tft_t4.cpp create mode 100644 src/tft/Arial_14.cpp create mode 100644 src/tft/Arial_19.cpp diff --git a/platformio.ini b/platformio.ini index 4ac8ac47..7d7fbaf0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -35,6 +35,7 @@ build_flags = -Isrc/n64 -Isrc/printf -Isrc/tinyalloc + -Isrc/lib ; Printf Configuration -DPRINTF_DISABLE_SUPPORT_FLOAT diff --git a/src/lib/GuiLite.h b/src/lib/GuiLite.h new file mode 100644 index 00000000..8ad6dd15 --- /dev/null +++ b/src/lib/GuiLite.h @@ -0,0 +1,4337 @@ +#pragma once + +#define REAL_TIME_TASK_CYCLE_MS 50 +#define MAX(a,b) (((a)>(b))?(a):(b)) +#define MIN(a,b) (((a)<(b))?(a):(b)) + +#define GL_ARGB(a, r, g, b) ((((unsigned int)(a)) << 24) | (((unsigned int)(r)) << 16) | (((unsigned int)(g)) << 8) | ((unsigned int)(b))) +#define GL_ARGB_A(rgb) ((((unsigned int)(rgb)) >> 24) & 0xFF) + +#define GL_RGB(r, g, b) ((0xFF << 24) | (((unsigned int)(r)) << 16) | (((unsigned int)(g)) << 8) | ((unsigned int)(b))) +#define GL_RGB_R(rgb) ((((unsigned int)(rgb)) >> 16) & 0xFF) +#define GL_RGB_G(rgb) ((((unsigned int)(rgb)) >> 8) & 0xFF) +#define GL_RGB_B(rgb) (((unsigned int)(rgb)) & 0xFF) +#define GL_RGB_32_to_16(rgb) (((((unsigned int)(rgb)) & 0xFF) >> 3) | ((((unsigned int)(rgb)) & 0xFC00) >> 5) | ((((unsigned int)(rgb)) & 0xF80000) >> 8)) +#define GL_RGB_16_to_32(rgb) ((0xFF << 24) | ((((unsigned int)(rgb)) & 0x1F) << 3) | ((((unsigned int)(rgb)) & 0x7E0) << 5) | ((((unsigned int)(rgb)) & 0xF800) << 8)) + +#define ALIGN_HCENTER 0x00000000L +#define ALIGN_LEFT 0x01000000L +#define ALIGN_RIGHT 0x02000000L +#define ALIGN_HMASK 0x03000000L + +#define ALIGN_VCENTER 0x00000000L +#define ALIGN_TOP 0x00100000L +#define ALIGN_BOTTOM 0x00200000L +#define ALIGN_VMASK 0x00300000L + +typedef struct +{ + unsigned short year; + unsigned short month; + unsigned short date; + unsigned short day; + unsigned short hour; + unsigned short minute; + unsigned short second; +}T_TIME; + +void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)); +void _assert(const char* file, int line); +#define ASSERT(condition) \ + do{ \ + if(!(condition))_assert(__FILE__, __LINE__);\ + }while(0) +void log_out(const char* log); + +long get_time_in_second(); +T_TIME second_to_day(long second); +T_TIME get_time(); + +void start_real_timer(void (*func)(void* arg)); +void register_timer(int milli_second, void func(void* param), void* param); + +unsigned int get_cur_thread_id(); +void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg); +void thread_sleep(unsigned int milli_seconds); +int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data); + +#define FIFO_BUFFER_LEN 1024 +class c_fifo +{ +public: + c_fifo(); + int read(void* buf, int len); + int write(void* buf, int len); +private: + unsigned char m_buf[FIFO_BUFFER_LEN]; + int m_head; + int m_tail; + void* m_read_sem; + void* m_write_mutex; +}; + +class c_rect +{ +public: + c_rect(){ m_left = m_top = m_right = m_bottom = -1; } + c_rect(int left, int top, int width, int height) + { + set_rect(left, top, width, height); + } + void set_rect(int left, int top, int width, int height) + { + ASSERT(width > 0 && height > 0); + m_left = left; + m_top = top; + m_right = left + width - 1; + m_bottom = top + height -1; + } + bool pt_in_rect(int x, int y) const + { + return x >= m_left && x <= m_right && y >= m_top && y <= m_bottom; + } + int operator==(const c_rect& rect) const + { + return (m_left == rect.m_left) && (m_top == rect.m_top) && (m_right == rect.m_right) && (m_bottom == rect.m_bottom); + } + int width() const { return m_right - m_left + 1; } + int height() const { return m_bottom - m_top + 1 ; } + + int m_left; + int m_top; + int m_right; + int m_bottom; +}; +//BITMAP +typedef struct struct_bitmap_info +{ + unsigned short width; + unsigned short height; + unsigned short color_bits;//support 16 bits only + const unsigned short* pixel_color_array; +} BITMAP_INFO; +//FONT +typedef struct struct_lattice +{ + unsigned int utf8_code; + unsigned char width; + const unsigned char* pixel_buffer; +} LATTICE; +typedef struct struct_lattice_font_info +{ + unsigned char height; + unsigned int count; + LATTICE* lattice_array; +} LATTICE_FONT_INFO; +//Rebuild gui library once you change this file +enum FONT_LIST +{ + FONT_NULL, + FONT_DEFAULT, + FONT_CUSTOM1, + FONT_CUSTOM2, + FONT_CUSTOM3, + FONT_CUSTOM4, + FONT_CUSTOM5, + FONT_CUSTOM6, + FONT_MAX +}; +enum IMAGE_LIST +{ + IMAGE_CUSTOM1, + IMAGE_CUSTOM2, + IMAGE_CUSTOM3, + IMAGE_CUSTOM4, + IMAGE_CUSTOM5, + IMAGE_CUSTOM6, + IMAGE_MAX +}; +enum COLOR_LIST +{ + COLOR_WND_FONT, + COLOR_WND_NORMAL, + COLOR_WND_PUSHED, + COLOR_WND_FOCUS, + COLOR_WND_BORDER, + COLOR_CUSTOME1, + COLOR_CUSTOME2, + COLOR_CUSTOME3, + COLOR_CUSTOME4, + COLOR_CUSTOME5, + COLOR_CUSTOME6, + COLOR_MAX +}; +class c_theme +{ +public: + static int add_font(FONT_LIST index, const void* font) + { + if (index >= FONT_MAX) + { + ASSERT(false); + return -1; + } + s_font_map[index] = font; + return 0; + } + static const void* get_font(FONT_LIST index) + { + if (index >= FONT_MAX) + { + ASSERT(false); + return 0; + } + return s_font_map[index]; + } + static int add_image(IMAGE_LIST index, const void* image_info) + { + if (index >= IMAGE_MAX) + { + ASSERT(false); + return -1; + } + s_image_map[index] = image_info; + return 0; + } + static const void* get_image(IMAGE_LIST index) + { + if (index >= IMAGE_MAX) + { + ASSERT(false); + return 0; + } + return s_image_map[index]; + } + + static int add_color(COLOR_LIST index, const unsigned int color) + { + if (index >= COLOR_MAX) + { + ASSERT(false); + return -1; + } + s_color_map[index] = color; + return 0; + } + static const unsigned int get_color(COLOR_LIST index) + { + if (index >= COLOR_MAX) + { + ASSERT(false); + return 0; + } + return s_color_map[index]; + } +private: + static const void* s_font_map[FONT_MAX]; + static const void* s_image_map[IMAGE_MAX]; + static unsigned int s_color_map[COLOR_MAX]; +}; +#include +#include +#include +#define SURFACE_CNT_MAX 6//root + pages +typedef enum +{ + Z_ORDER_LEVEL_0,//lowest graphic level + Z_ORDER_LEVEL_1,//middle graphic level + Z_ORDER_LEVEL_2,//highest graphic level + Z_ORDER_LEVEL_MAX +}Z_ORDER_LEVEL; +struct EXTERNAL_GFX_OP +{ + void(*draw_pixel)(int x, int y, unsigned int rgb); + void(*fill_rect)(int x0, int y0, int x1, int y1, unsigned int rgb); +}; +class c_surface; +class c_display { + friend class c_surface; +public: + inline c_display(void* phy_fb, int display_width, int display_height, int surface_width, int surface_height, unsigned int color_bytes, int surface_cnt, EXTERNAL_GFX_OP* gfx_op = 0);//multiple surface or surface_no_fb + inline c_display(void* phy_fb, int display_width, int display_height, c_surface* surface);//single custom surface + inline c_surface* alloc_surface(Z_ORDER_LEVEL max_zorder, c_rect layer_rect = c_rect());//for multiple surfaces + inline int swipe_surface(c_surface* s0, c_surface* s1, int x0, int x1, int y0, int y1, int offset); + int get_width() { return m_width; } + int get_height() { return m_height; } + void* get_updated_fb(int* width, int* height, bool force_update = false) + { + if (width && height) + { + *width = get_width(); + *height = get_height(); + } + if (force_update) + { + return m_phy_fb; + } + if (m_phy_read_index == m_phy_write_index) + {//No update + return 0; + } + m_phy_read_index = m_phy_write_index; + return m_phy_fb; + } + int snap_shot(const char* file_name) + { + if (!m_phy_fb || (m_color_bytes !=2 && m_color_bytes != 4)) + { + return -1; + } + int width = get_width(); + int height = get_height(); + //16 bits framebuffer + if (m_color_bytes == 2) + { + return build_bmp(file_name, width, height, (unsigned char*)m_phy_fb); + } + //32 bits framebuffer + unsigned short* p_bmp565_data = new unsigned short[width * height]; + unsigned int* p_raw_data = (unsigned int*)m_phy_fb; + for (int i = 0; i < width * height; i++) + { + unsigned int rgb = *p_raw_data++; + p_bmp565_data[i] = GL_RGB_32_to_16(rgb); + } + int ret = build_bmp(file_name, width, height, (unsigned char*)p_bmp565_data); + delete[]p_bmp565_data; + return ret; + } +private: + int m_width; //in pixels + int m_height; //in pixels + int m_color_bytes; //16 bits, 32 bits only + void* m_phy_fb; //physical framebuffer + int m_phy_read_index; + int m_phy_write_index; + c_surface* m_surface_group[SURFACE_CNT_MAX]; + int m_surface_cnt; //surface count + int m_surface_index; +}; +class c_layer +{ +public: + c_layer() { fb = 0; } + void* fb; //framebuffer + c_rect rect; //framebuffer area +}; +class c_surface { + friend class c_display; friend class c_bitmap_operator; +public: + c_surface(unsigned int width, unsigned int height, unsigned int color_bytes, Z_ORDER_LEVEL max_zorder = Z_ORDER_LEVEL_0, c_rect overlpa_rect = c_rect()) : m_width(width), m_height(height), m_color_bytes(color_bytes), m_fb(0), m_is_active(false), m_top_zorder(Z_ORDER_LEVEL_0), m_phy_fb(0), m_phy_write_index(0), m_display(0) + { + (overlpa_rect == c_rect()) ? set_surface(max_zorder, c_rect(0, 0, width - 1, height - 1)) : set_surface(max_zorder, overlpa_rect); + } + int get_width() { return m_width; } + int get_height() { return m_height; } + unsigned int get_pixel(int x, int y, unsigned int z_order) + { + if (x >= m_width || y >= m_height || x < 0 || y < 0 || z_order >= Z_ORDER_LEVEL_MAX) + { + ASSERT(false); + return 0; + } + if (m_layers[z_order].fb) + { + return (m_color_bytes == 4) ? ((unsigned int*)(m_layers[z_order].fb))[y * m_width + x] : GL_RGB_16_to_32(((unsigned short*)(m_layers[z_order].fb))[y * m_width + x]); + } + else if (m_fb) + { + return (m_color_bytes == 4) ? ((unsigned int*)m_fb)[y * m_width + x] : GL_RGB_16_to_32(((unsigned short*)m_fb)[y * m_width + x]); + } + else if (m_phy_fb) + { + return (m_color_bytes == 4) ? ((unsigned int*)m_phy_fb)[y * m_width + x] : GL_RGB_16_to_32(((unsigned short*)m_phy_fb)[y * m_width + x]); + } + return 0; + } + virtual void draw_pixel(int x, int y, unsigned int rgb, unsigned int z_order) + { + if (x >= m_width || y >= m_height || x < 0 || y < 0) + { + return; + } + if (z_order > (unsigned int)m_max_zorder) + { + ASSERT(false); + return; + } + if (z_order == m_max_zorder) + { + return draw_pixel_on_fb(x, y, rgb); + } + + if (z_order > (unsigned int)m_top_zorder) + { + m_top_zorder = (Z_ORDER_LEVEL)z_order; + } + if (m_layers[z_order].rect.pt_in_rect(x, y)) + { + c_rect layer_rect = m_layers[z_order].rect; + if (m_color_bytes == 4) + { + ((unsigned int*)(m_layers[z_order].fb))[(x - layer_rect.m_left) + (y - layer_rect.m_top) * layer_rect.width()] = rgb; + } + else + { + ((unsigned short*)(m_layers[z_order].fb))[(x - layer_rect.m_left) + (y - layer_rect.m_top) * layer_rect.width()] = GL_RGB_32_to_16(rgb); + } + } + + if (z_order == m_top_zorder) + { + return draw_pixel_on_fb(x, y, rgb); + } + bool be_overlapped = false; + for (unsigned int tmp_z_order = Z_ORDER_LEVEL_MAX - 1; tmp_z_order > z_order; tmp_z_order--) + { + if (m_layers[tmp_z_order].rect.pt_in_rect(x, y)) + { + be_overlapped = true; + break; + } + } + if (!be_overlapped) + { + draw_pixel_on_fb(x, y, rgb); + } + } + virtual void fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb, unsigned int z_order) + { + x0 = (x0 < 0) ? 0 : x0; + y0 = (y0 < 0) ? 0 : y0; + x1 = (x1 > (m_width - 1)) ? (m_width - 1) : x1; + y1 = (y1 > (m_height - 1)) ? (m_height - 1) : y1; + if (z_order == m_max_zorder) + { + return fill_rect_on_fb(x0, y0, x1, y1, rgb); + } + if (z_order == m_top_zorder) + { + int x, y; + c_rect layer_rect = m_layers[z_order].rect; + unsigned int rgb_16 = GL_RGB_32_to_16(rgb); + for (y = y0; y <= y1; y++) + { + for (x = x0; x <= x1; x++) + { + if (layer_rect.pt_in_rect(x, y)) + { + if (m_color_bytes == 4) + { + ((unsigned int*)m_layers[z_order].fb)[(y - layer_rect.m_top) * layer_rect.width() + (x - layer_rect.m_left)] = rgb; + } + else + { + ((unsigned short*)m_layers[z_order].fb)[(y - layer_rect.m_top) * layer_rect.width() + (x - layer_rect.m_left)] = rgb_16; + } + } + } + } + return fill_rect_on_fb(x0, y0, x1, y1, rgb); + } + for (; y0 <= y1; y0++) + { + draw_hline(x0, x1, y0, rgb, z_order); + } + } + void draw_hline(int x0, int x1, int y, unsigned int rgb, unsigned int z_order) + { + for (; x0 <= x1; x0++) + { + draw_pixel(x0, y, rgb, z_order); + } + } + void draw_vline(int x, int y0, int y1, unsigned int rgb, unsigned int z_order) + { + for (; y0 <= y1; y0++) + { + draw_pixel(x, y0, rgb, z_order); + } + } + void draw_line(int x1, int y1, int x2, int y2, unsigned int rgb, unsigned int z_order) + { + int dx, dy, x, y, e; + (x1 > x2) ? (dx = x1 - x2) : (dx = x2 - x1); + (y1 > y2) ? (dy = y1 - y2) : (dy = y2 - y1); + if (((dx > dy) && (x1 > x2)) || ((dx <= dy) && (y1 > y2))) + { + x = x2; y = y2; + x2 = x1; y2 = y1; + x1 = x; y1 = y; + } + x = x1; y = y1; + if (dx > dy) + { + e = dy - dx / 2; + for (; x1 <= x2; ++x1, e += dy) + { + draw_pixel(x1, y1, rgb, z_order); + if (e > 0) { e -= dx; (y > y2) ? --y1 : ++y1; } + } + } + else + { + e = dx - dy / 2; + for (; y1 <= y2; ++y1, e += dx) + { + draw_pixel(x1, y1, rgb, z_order); + if (e > 0) { e -= dy; (x > x2) ? --x1 : ++x1; } + } + } + } + void draw_rect(int x0, int y0, int x1, int y1, unsigned int rgb, unsigned int z_order, unsigned int size = 1) + { + for (unsigned int offset = 0; offset < size; offset++) + { + draw_hline(x0 + offset, x1 - offset, y0 + offset, rgb, z_order); + draw_hline(x0 + offset, x1 - offset, y1 - offset, rgb, z_order); + draw_vline(x0 + offset, y0 + offset, y1 - offset, rgb, z_order); + draw_vline(x1 - offset, y0 + offset, y1 - offset, rgb, z_order); + } + } + void draw_rect(c_rect rect, unsigned int rgb, unsigned int size, unsigned int z_order) + { + draw_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, rgb, z_order, size); + } + void fill_rect(c_rect rect, unsigned int rgb, unsigned int z_order) + { + fill_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, rgb, z_order); + } + int flush_screen(int left, int top, int right, int bottom) + { + if (left < 0 || left >= m_width || right < 0 || right >= m_width || + top < 0 || top >= m_height || bottom < 0 || bottom >= m_height) + { + ASSERT(false); + } + if (!m_is_active || (0 == m_phy_fb) || (0 == m_fb)) + { + return -1; + } + int display_width = m_display->get_width(); + int display_height = m_display->get_height(); + left = (left >= display_width) ? (display_width - 1) : left; + right = (right >= display_width) ? (display_width - 1) : right; + top = (top >= display_height) ? (display_height - 1) : top; + bottom = (bottom >= display_height) ? (display_height - 1) : bottom; + for (int y = top; y < bottom; y++) + { + void* s_addr = (char*)m_fb + ((y * m_width + left) * m_color_bytes); + void* d_addr = (char*)m_phy_fb + ((y * display_width + left) * m_color_bytes); + memcpy(d_addr, s_addr, (right - left) * m_color_bytes); + } + *m_phy_write_index = *m_phy_write_index + 1; + return 0; + } + bool is_active() { return m_is_active; } + c_display* get_display() { return m_display; } + int show_layer(c_rect& rect, unsigned int z_order) + { + ASSERT(z_order >= Z_ORDER_LEVEL_0 && z_order < Z_ORDER_LEVEL_MAX); + c_rect layer_rect = m_layers[z_order].rect; + ASSERT(rect.m_left >= layer_rect.m_left && rect.m_right <= layer_rect.m_right && + rect.m_top >= layer_rect.m_top && rect.m_bottom <= layer_rect.m_bottom); + void* fb = m_layers[z_order].fb; + int width = layer_rect.width(); + for (int y = rect.m_top; y <= rect.m_bottom; y++) + { + for (int x = rect.m_left; x <= rect.m_right; x++) + { + unsigned int rgb = (m_color_bytes == 4) ? ((unsigned int*)fb)[(x - layer_rect.m_left) + (y - layer_rect.m_top) * width] : GL_RGB_16_to_32(((unsigned short*)fb)[(x - layer_rect.m_left) + (y - layer_rect.m_top) * width]); + draw_pixel_on_fb(x, y, rgb); + } + } + return 0; + } + void set_active(bool flag) { m_is_active = flag; } +protected: + virtual void fill_rect_on_fb(int x0, int y0, int x1, int y1, unsigned int rgb) + { + int display_width = m_display->get_width(); + int display_height = m_display->get_height(); + if (m_color_bytes == 4) + { + int x; + unsigned int* fb, * phy_fb; + for (; y0 <= y1; y0++) + { + x = x0; + fb = m_fb ? &((unsigned int*)m_fb)[y0 * m_width + x] : 0; + phy_fb = &((unsigned int*)m_phy_fb)[y0 * display_width + x]; + *m_phy_write_index = *m_phy_write_index + 1; + for (; x <= x1; x++) + { + if (fb) + { + *fb++ = rgb; + } + if (m_is_active && (x < display_width) && (y0 < display_height)) + { + *phy_fb++ = rgb; + } + } + } + } + else if (m_color_bytes == 2) + { + int x; + unsigned short* fb, * phy_fb; + rgb = GL_RGB_32_to_16(rgb); + for (; y0 <= y1; y0++) + { + x = x0; + fb = m_fb ? &((unsigned short*)m_fb)[y0 * m_width + x] : 0; + phy_fb = &((unsigned short*)m_phy_fb)[y0 * display_width + x]; + *m_phy_write_index = *m_phy_write_index + 1; + for (; x <= x1; x++) + { + if (fb) + { + *fb++ = rgb; + } + if (m_is_active && (x < display_width) && (y0 < display_height)) + { + *phy_fb++ = rgb; + } + } + } + } + } + virtual void draw_pixel_on_fb(int x, int y, unsigned int rgb) + { + if (m_fb) + { + (m_color_bytes == 4) ? ((unsigned int*)m_fb)[y * m_width + x] = rgb : ((unsigned short*)m_fb)[y * m_width + x] = GL_RGB_32_to_16(rgb); + } + if (m_is_active && (x < m_display->get_width()) && (y < m_display->get_height())) + { + if (m_color_bytes == 4) + { + ((unsigned int*)m_phy_fb)[y * (m_display->get_width()) + x] = rgb; + } + else + { + ((unsigned short*)m_phy_fb)[y * (m_display->get_width()) + x] = GL_RGB_32_to_16(rgb); + } + *m_phy_write_index = *m_phy_write_index + 1; + } + } + void attach_display(c_display* display) + { + ASSERT(display); + m_display = display; + m_phy_fb = display->m_phy_fb; + m_phy_write_index = &display->m_phy_write_index; + } + void set_surface(Z_ORDER_LEVEL max_z_order, c_rect layer_rect) + { + m_max_zorder = max_z_order; + if (m_display && (m_display->m_surface_cnt > 1)) + { + m_fb = calloc(m_width * m_height, m_color_bytes); + } + for (int i = Z_ORDER_LEVEL_0; i < m_max_zorder; i++) + {//Top layber fb always be 0 + ASSERT(m_layers[i].fb = calloc(layer_rect.width() * layer_rect.height(), m_color_bytes)); + m_layers[i].rect = layer_rect; + } + } + int m_width; //in pixels + int m_height; //in pixels + int m_color_bytes; //16 bits, 32 bits only + void* m_fb; //frame buffer you could see + c_layer m_layers[Z_ORDER_LEVEL_MAX];//all graphic layers + bool m_is_active; //active flag + Z_ORDER_LEVEL m_max_zorder; //the highest graphic layer the surface will have + Z_ORDER_LEVEL m_top_zorder; //the current highest graphic layer the surface have + void* m_phy_fb; //physical framebufer + int* m_phy_write_index; + c_display* m_display; +}; +class c_surface_no_fb : public c_surface {//No physical framebuffer, render with external graphic interface + friend class c_display; +public: + c_surface_no_fb(unsigned int width, unsigned int height, unsigned int color_bytes, struct EXTERNAL_GFX_OP* gfx_op, Z_ORDER_LEVEL max_zorder = Z_ORDER_LEVEL_0, c_rect overlpa_rect = c_rect()) : c_surface(width, height, color_bytes, max_zorder, overlpa_rect), m_gfx_op(gfx_op) {} +protected: + virtual void fill_rect_on_fb(int x0, int y0, int x1, int y1, unsigned int rgb) + { + if (!m_gfx_op) + { + return; + } + if (m_gfx_op->fill_rect) + { + return m_gfx_op->fill_rect(x0, y0, x1, y1, rgb); + } + if (m_gfx_op->draw_pixel && m_is_active) + { + for (int y = y0; y <= y1; y++) + { + for (int x = x0; x <= x1; x++) + { + m_gfx_op->draw_pixel(x, y, rgb); + } + } + } + if (!m_fb) { return; } + if (m_color_bytes == 4) + { + unsigned int* fb; + for (int y = y0; y <= y1; y++) + { + fb = &((unsigned int*)m_fb)[y0 * m_width + x0]; + for (int x = x0; x <= x1; x++) + { + *fb++ = rgb; + } + } + } + else if (m_color_bytes == 2) + { + unsigned short* fb; + rgb = GL_RGB_32_to_16(rgb); + for (int y = y0; y <= y1; y++) + { + fb = &((unsigned short*)m_fb)[y0 * m_width + x0]; + for (int x = x0; x <= x1; x++) + { + *fb++ = rgb; + } + } + } + } + virtual void draw_pixel_on_fb(int x, int y, unsigned int rgb) + { + if (m_gfx_op && m_gfx_op->draw_pixel && m_is_active) + { + m_gfx_op->draw_pixel(x, y, rgb); + } + if (!m_fb) { return; } + if (m_color_bytes == 4) + { + ((unsigned int*)m_fb)[y * m_width + x] = rgb; + } + else if (m_color_bytes == 2) + { + ((unsigned short*)m_fb)[y * m_width + x] = GL_RGB_32_to_16(rgb); + } + } + struct EXTERNAL_GFX_OP* m_gfx_op;//Rendering by external method +}; +inline c_display::c_display(void* phy_fb, int display_width, int display_height, int surface_width, int surface_height, unsigned int color_bytes, int surface_cnt, EXTERNAL_GFX_OP* gfx_op) : m_width(display_width), m_height(display_height), m_color_bytes(color_bytes), m_phy_fb(phy_fb), m_phy_read_index(0), m_phy_write_index(0), m_surface_cnt(surface_cnt), m_surface_index(0) +{ + ASSERT(color_bytes == 2 || color_bytes == 4); + ASSERT(m_surface_cnt <= SURFACE_CNT_MAX); + memset(m_surface_group, 0, sizeof(m_surface_group)); + + for (int i = 0; i < m_surface_cnt; i++) + { + m_surface_group[i] = (phy_fb) ? new c_surface(surface_width, surface_height, color_bytes) : new c_surface_no_fb(surface_width, surface_height, color_bytes, gfx_op); + m_surface_group[i]->attach_display(this); + } +} +inline c_display::c_display(void* phy_fb, int display_width, int display_height, c_surface* surface) : m_width(display_width), m_height(display_height), m_phy_fb(phy_fb), m_phy_read_index(0), m_phy_write_index(0), m_surface_cnt(1), m_surface_index(0) +{ + m_color_bytes = surface->m_color_bytes; + surface->m_is_active = true; + (m_surface_group[0] = surface)->attach_display(this); +} +inline c_surface* c_display::alloc_surface(Z_ORDER_LEVEL max_zorder, c_rect layer_rect) +{ + ASSERT(max_zorder < Z_ORDER_LEVEL_MAX && m_surface_index < m_surface_cnt); + (layer_rect == c_rect()) ? m_surface_group[m_surface_index]->set_surface(max_zorder, c_rect(0, 0, m_width - 1, m_height - 1)) : m_surface_group[m_surface_index]->set_surface(max_zorder, layer_rect); + return m_surface_group[m_surface_index++]; +} +inline int c_display::swipe_surface(c_surface* s0, c_surface* s1, int x0, int x1, int y0, int y1, int offset) +{ + int surface_width = s0->get_width(); + int surface_height = s0->get_height(); + if (offset < 0 || offset > surface_width || y0 < 0 || y0 >= surface_height || + y1 < 0 || y1 >= surface_height || x0 < 0 || x0 >= surface_width || x1 < 0 || x1 >= surface_width) + { + ASSERT(false); + return -1; + } + int width = (x1 - x0 + 1); + if (width < 0 || width > surface_width || width < offset) + { + ASSERT(false); + return -1; + } + x0 = (x0 >= m_width) ? (m_width - 1) : x0; + x1 = (x1 >= m_width) ? (m_width - 1) : x1; + y0 = (y0 >= m_height) ? (m_height - 1) : y0; + y1 = (y1 >= m_height) ? (m_height - 1) : y1; + if (m_phy_fb) + { + for (int y = y0; y <= y1; y++) + { + //Left surface + char* addr_s = ((char*)(s0->m_fb) + (y * (s0->get_width()) + x0 + offset) * m_color_bytes); + char* addr_d = ((char*)(m_phy_fb)+(y * m_width + x0) * m_color_bytes); + memcpy(addr_d, addr_s, (width - offset) * m_color_bytes); + //Right surface + addr_s = ((char*)(s1->m_fb) + (y * (s1->get_width()) + x0) * m_color_bytes); + addr_d = ((char*)(m_phy_fb)+(y * m_width + x0 + (width - offset)) * m_color_bytes); + memcpy(addr_d, addr_s, offset * m_color_bytes); + } + } + else if (m_color_bytes == 4) + { + void(*draw_pixel)(int x, int y, unsigned int rgb) = ((c_surface_no_fb*)s0)->m_gfx_op->draw_pixel; + for (int y = y0; y <= y1; y++) + { + //Left surface + for (int x = x0; x <= (x1 - offset); x++) + { + draw_pixel(x, y, ((unsigned int*)s0->m_fb)[y * m_width + x + offset]); + } + //Right surface + for (int x = x1 - offset; x <= x1; x++) + { + draw_pixel(x, y, ((unsigned int*)s1->m_fb)[y * m_width + x + offset - x1 + x0]); + } + } + } + else if (m_color_bytes == 2) + { + void(*draw_pixel)(int x, int y, unsigned int rgb) = ((c_surface_no_fb*)s0)->m_gfx_op->draw_pixel; + for (int y = y0; y <= y1; y++) + { + //Left surface + for (int x = x0; x <= (x1 - offset); x++) + { + draw_pixel(x, y, GL_RGB_16_to_32(((unsigned short*)s0->m_fb)[y * m_width + x + offset])); + } + //Right surface + for (int x = x1 - offset; x <= x1; x++) + { + draw_pixel(x, y, GL_RGB_16_to_32(((unsigned short*)s1->m_fb)[y * m_width + x + offset - x1 + x0])); + } + } + } + m_phy_write_index++; + return 0; +} +#include +#include +#define VALUE_STR_LEN 16 +class c_surface; +class c_font_operator +{ +public: + virtual void draw_string(c_surface* surface, int z_order, const void* string, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) = 0; + virtual void draw_string_in_rect(c_surface* surface, int z_order, const void* string, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) = 0; + virtual void draw_value(c_surface* surface, int z_order, int value, int dot_position, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) = 0; + virtual void draw_value_in_rect(c_surface* surface, int z_order, int value, int dot_position, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) = 0; + virtual int get_str_size(const void* string, const void* font, int& width, int& height) = 0; + void get_string_pos(const void* string, const void* font, c_rect rect, unsigned int align_type, int& x, int& y) + { + int x_size, y_size; + get_str_size(string, font, x_size, y_size); + int height = rect.m_bottom - rect.m_top + 1; + int width = rect.m_right - rect.m_left + 1; + x = y = 0; + switch (align_type & ALIGN_HMASK) + { + case ALIGN_HCENTER: + //m_text_org_x=0 + if (width > x_size) + { + x = (width - x_size) / 2; + } + break; + case ALIGN_LEFT: + x = 0; + break; + case ALIGN_RIGHT: + //m_text_org_x=0 + if (width > x_size) + { + x = width - x_size; + } + break; + default: + ASSERT(0); + break; + } + switch (align_type & ALIGN_VMASK) + { + case ALIGN_VCENTER: + //m_text_org_y=0 + if (height > y_size) + { + y = (height - y_size) / 2; + } + break; + case ALIGN_TOP: + y = 0; + break; + case ALIGN_BOTTOM: + //m_text_org_y=0 + if (height > y_size) + { + y = height - y_size; + } + break; + default: + ASSERT(0); + break; + } + } +}; +class c_lattice_font_op : public c_font_operator +{ +public: + void draw_string(c_surface* surface, int z_order, const void* string, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) + { + const char* s = (const char*)string; + if (0 == s) + { + return; + } + int offset = 0; + unsigned int utf8_code; + while (*s) + { + s += get_utf8_code(s, utf8_code); + offset += draw_single_char(surface, z_order, utf8_code, (x + offset), y, (const LATTICE_FONT_INFO*)font, font_color, bg_color); + } + } + void draw_string_in_rect(c_surface* surface, int z_order, const void* string, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) + { + const char* s = (const char*)string; + if (0 == s) + { + return; + } + int x, y; + get_string_pos(s, (const LATTICE_FONT_INFO*)font, rect, align_type, x, y); + draw_string(surface, z_order, string, rect.m_left + x, rect.m_top + y, font, font_color, bg_color); + } + void draw_value(c_surface* surface, int z_order, int value, int dot_position, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) + { + char buf[VALUE_STR_LEN]; + value_2_string(value, dot_position, buf, VALUE_STR_LEN); + draw_string(surface, z_order, buf, x, y, (const LATTICE_FONT_INFO*)font, font_color, bg_color); + } + void draw_value_in_rect(c_surface* surface, int z_order, int value, int dot_position, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) + { + char buf[VALUE_STR_LEN]; + value_2_string(value, dot_position, buf, VALUE_STR_LEN); + draw_string_in_rect(surface, z_order, buf, rect, (const LATTICE_FONT_INFO*)font, font_color, bg_color, align_type); + } + int get_str_size(const void *string, const void* font, int& width, int& height) + { + const char* s = (const char*)string; + if (0 == s || 0 == font) + { + width = height = 0; + return -1; + } + int lattice_width = 0; + unsigned int utf8_code; + int utf8_bytes; + while (*s) + { + utf8_bytes = get_utf8_code(s, utf8_code); + const LATTICE* p_lattice = get_lattice((const LATTICE_FONT_INFO*)font, utf8_code); + lattice_width += p_lattice ? p_lattice->width : ((const LATTICE_FONT_INFO*)font)->height; + s += utf8_bytes; + } + width = lattice_width; + height = ((const LATTICE_FONT_INFO*)font)->height; + return 0; + } +private: + void value_2_string(int value, int dot_position, char* buf, int len) + { + memset(buf, 0, len); + switch (dot_position) + { + case 0: + sprintf(buf, "%d", value); + break; + case 1: + sprintf(buf, "%.1f", value * 1.0 / 10); + break; + case 2: + sprintf(buf, "%.2f", value * 1.0 / 100); + break; + case 3: + sprintf(buf, "%.3f", value * 1.0 / 1000); + break; + default: + ASSERT(false); + break; + } + } + int draw_single_char(c_surface* surface, int z_order, unsigned int utf8_code, int x, int y, const LATTICE_FONT_INFO* font, unsigned int font_color, unsigned int bg_color) + { + unsigned int error_color = 0xFFFFFFFF; + if (font) + { + const LATTICE* p_lattice = get_lattice(font, utf8_code); + if (p_lattice) + { + draw_lattice(surface, z_order, x, y, p_lattice->width, font->height, p_lattice->pixel_buffer, font_color, bg_color); + return p_lattice->width; + } + } + else + { + error_color = GL_RGB(255, 0, 0); + } + //lattice/font not found, draw "X" + int len = 16; + for (int y_ = 0; y_ < len; y_++) + { + for (int x_ = 0; x_ < len; x_++) + { + int diff = (x_ - y_); + int sum = (x_ + y_); + (diff == 0 || diff == -1 || diff == 1 || sum == len || sum == (len - 1) || sum == (len + 1)) ? + surface->draw_pixel((x + x_), (y + y_), error_color, z_order) : surface->draw_pixel((x + x_), (y + y_), 0, z_order); + } + } + return len; + } + void draw_lattice(c_surface* surface, int z_order, int x, int y, int width, int height, const unsigned char* p_data, unsigned int font_color, unsigned int bg_color) + { + unsigned int r, g, b, rgb; + unsigned char blk_value = *p_data++; + unsigned char blk_cnt = *p_data++; + b = (GL_RGB_B(font_color) * blk_value + GL_RGB_B(bg_color) * (255 - blk_value)) >> 8; + g = (GL_RGB_G(font_color) * blk_value + GL_RGB_G(bg_color) * (255 - blk_value)) >> 8; + r = (GL_RGB_R(font_color) * blk_value + GL_RGB_R(bg_color) * (255 - blk_value)) >> 8; + rgb = GL_RGB(r, g, b); + for (int y_ = 0; y_ < height; y_++) + { + for (int x_ = 0; x_ < width; x_++) + { + ASSERT(blk_cnt); + if (0x00 == blk_value) + { + if (GL_ARGB_A(bg_color)) + { + surface->draw_pixel(x + x_, y + y_, bg_color, z_order); + } + } + else + { + surface->draw_pixel((x + x_), (y + y_), rgb, z_order); + } + if (--blk_cnt == 0) + {//reload new block + blk_value = *p_data++; + blk_cnt = *p_data++; + b = (GL_RGB_B(font_color) * blk_value + GL_RGB_B(bg_color) * (255 - blk_value)) >> 8; + g = (GL_RGB_G(font_color) * blk_value + GL_RGB_G(bg_color) * (255 - blk_value)) >> 8; + r = (GL_RGB_R(font_color) * blk_value + GL_RGB_R(bg_color) * (255 - blk_value)) >> 8; + rgb = GL_RGB(r, g, b); + } + } + } + } + + const LATTICE* get_lattice(const LATTICE_FONT_INFO* font, unsigned int utf8_code) + { + int first = 0; + int last = font->count - 1; + int middle = (first + last) / 2; + while (first <= last) + { + if (font->lattice_array[middle].utf8_code < utf8_code) + first = middle + 1; + else if (font->lattice_array[middle].utf8_code == utf8_code) + { + return &font->lattice_array[middle]; + } + else + { + last = middle - 1; + } + middle = (first + last) / 2; + } + return 0; + } + + static int get_utf8_code(const char* s, unsigned int& output_utf8_code) + { + static unsigned char s_utf8_length_table[256] = + { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1 + }; + unsigned char* us = (unsigned char*)s; + int utf8_bytes = s_utf8_length_table[*us]; + switch (utf8_bytes) + { + case 1: + output_utf8_code = *us; + break; + case 2: + output_utf8_code = (*us << 8) | (*(us + 1)); + break; + case 3: + output_utf8_code = (*us << 16) | ((*(us + 1)) << 8) | *(us + 2); + break; + case 4: + output_utf8_code = (*us << 24) | ((*(us + 1)) << 16) | (*(us + 2) << 8) | *(us + 3); + break; + default: + ASSERT(false); + break; + } + return utf8_bytes; + } +}; +class c_word +{ +public: + static void draw_string(c_surface* surface, int z_order, const void* string, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color)//string: char or wchar_t + { + fontOperator->draw_string(surface, z_order, string, x, y, font, font_color, bg_color); + } + static void draw_string_in_rect(c_surface* surface, int z_order, const void* string, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT)//string: char or wchar_t + { + fontOperator->draw_string_in_rect(surface, z_order, string, rect, font, font_color, bg_color, align_type); + } + static void draw_value_in_rect(c_surface* surface, int z_order, int value, int dot_position, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) + { + fontOperator->draw_value_in_rect(surface, z_order, value, dot_position, rect, font, font_color, bg_color, align_type); + } + static void draw_value(c_surface* surface, int z_order, int value, int dot_position, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) + { + fontOperator->draw_value(surface, z_order, value, dot_position, x, y, font, font_color, bg_color); + } + + static int get_str_size(const void* string, const void* font, int& width, int& height) + { + return fontOperator->get_str_size(string, font, width, height); + } + static c_font_operator* fontOperator; +}; +#define DEFAULT_MASK_COLOR 0xFF080408 +class c_surface; +class c_image_operator +{ +public: + virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, unsigned int mask_rgb = DEFAULT_MASK_COLOR) = 0; + virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, int src_x, int src_y, int width, int height, unsigned int mask_rgb = DEFAULT_MASK_COLOR) = 0; +}; +class c_bitmap_operator : public c_image_operator +{ +public: + virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, unsigned int mask_rgb = DEFAULT_MASK_COLOR) + { + ASSERT(image_info); + BITMAP_INFO* pBitmap = (BITMAP_INFO*)image_info; + unsigned short* lower_fb_16 = 0; + unsigned int* lower_fb_32 = 0; + int lower_fb_width = 0; + c_rect lower_fb_rect; + if (z_order >= Z_ORDER_LEVEL_1) + { + lower_fb_16 = (unsigned short*)surface->m_layers[z_order - 1].fb; + lower_fb_32 = (unsigned int*)surface->m_layers[z_order - 1].fb; + lower_fb_rect = surface->m_layers[z_order - 1].rect; + lower_fb_width = lower_fb_rect.width(); + } + unsigned int mask_rgb_16 = GL_RGB_32_to_16(mask_rgb); + int xsize = pBitmap->width; + int ysize = pBitmap->height; + const unsigned short* pData = (const unsigned short*)pBitmap->pixel_color_array; + int color_bytes = surface->m_color_bytes; + for (int y_ = y; y_ < y + ysize; y_++) + { + for (int x_ = x; x_ < x + xsize; x_++) + { + unsigned int rgb = *pData++; + if (mask_rgb_16 == rgb) + { + if (lower_fb_rect.pt_in_rect(x_, y_)) + {//show lower layer + surface->draw_pixel(x_, y_, (color_bytes == 4) ? lower_fb_32[(y_ - lower_fb_rect.m_top) * lower_fb_width + (x_ - lower_fb_rect.m_left)] : GL_RGB_16_to_32(lower_fb_16[(y_ - lower_fb_rect.m_top) * lower_fb_width + (x_ - lower_fb_rect.m_left)]), z_order); + } + } + else + { + surface->draw_pixel(x_, y_, GL_RGB_16_to_32(rgb), z_order); + } + } + } + } + virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, int src_x, int src_y, int width, int height, unsigned int mask_rgb = DEFAULT_MASK_COLOR) + { + ASSERT(image_info); + BITMAP_INFO* pBitmap = (BITMAP_INFO*)image_info; + if (0 == pBitmap || (src_x + width > pBitmap->width) || (src_y + height > pBitmap->height)) + { + return; + } + unsigned short* lower_fb_16 = 0; + unsigned int* lower_fb_32 = 0; + int lower_fb_width = 0; + c_rect lower_fb_rect; + if (z_order >= Z_ORDER_LEVEL_1) + { + lower_fb_16 = (unsigned short*)surface->m_layers[z_order - 1].fb; + lower_fb_32 = (unsigned int*)surface->m_layers[z_order - 1].fb; + lower_fb_rect = surface->m_layers[z_order - 1].rect; + lower_fb_width = lower_fb_rect.width(); + } + unsigned int mask_rgb_16 = GL_RGB_32_to_16(mask_rgb); + const unsigned short* pData = (const unsigned short*)pBitmap->pixel_color_array; + int color_bytes = surface->m_color_bytes; + for (int y_ = 0; y_ < height; y_++) + { + const unsigned short* p = &pData[src_x + (src_y + y_) * pBitmap->width]; + for (int x_ = 0; x_ < width; x_++) + { + unsigned int rgb = *p++; + if (mask_rgb_16 == rgb) + { + if (lower_fb_rect.pt_in_rect(x + x_, y + y_)) + {//show lower layer + surface->draw_pixel(x + x_, y + y_, (color_bytes == 4) ? lower_fb_32[(y + y_ - lower_fb_rect.m_top) * lower_fb_width + x + x_ - lower_fb_rect.m_left] : GL_RGB_16_to_32(lower_fb_16[(y + y_ - lower_fb_rect.m_top) * lower_fb_width + x + x_ - lower_fb_rect.m_left]), z_order); + } + } + else + { + surface->draw_pixel(x + x_, y + y_, GL_RGB_16_to_32(rgb), z_order); + } + } + } + } +}; +class c_image +{ +public: + static void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, unsigned int mask_rgb = DEFAULT_MASK_COLOR) + { + image_operator->draw_image(surface, z_order, image_info, x, y, mask_rgb); + } + static void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, int src_x, int src_y, int width, int height, unsigned int mask_rgb = DEFAULT_MASK_COLOR) + { + image_operator->draw_image(surface, z_order, image_info, x, y, src_x, src_y, width, height, mask_rgb); + } + + static c_image_operator* image_operator; +}; +class c_wnd; +class c_surface; +typedef enum +{ + ATTR_VISIBLE = 0x40000000L, + ATTR_FOCUS = 0x20000000L, + ATTR_PRIORITY = 0x10000000L// Handle touch action at high priority +}WND_ATTRIBUTION; +typedef enum +{ + STATUS_NORMAL, + STATUS_PUSHED, + STATUS_FOCUSED, + STATUS_DISABLED +}WND_STATUS; +typedef enum +{ + NAV_FORWARD, + NAV_BACKWARD, + NAV_ENTER +}NAVIGATION_KEY; +typedef enum +{ + TOUCH_DOWN, + TOUCH_UP +}TOUCH_ACTION; +typedef struct struct_wnd_tree +{ + c_wnd* p_wnd;//window instance + unsigned int resource_id;//ID + const char* str;//caption + short x;//position x + short y;//position y + short width; + short height; + struct struct_wnd_tree* p_child_tree;//sub tree +}WND_TREE; +typedef void (c_wnd::*WND_CALLBACK)(int, int); +class c_wnd +{ +public: + c_wnd() : m_status(STATUS_NORMAL), m_attr((WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS)), m_parent(0), m_top_child(0), m_prev_sibling(0), m_next_sibling(0), + m_str(0), m_font_color(0), m_bg_color(0), m_id(0), m_z_order(Z_ORDER_LEVEL_0), m_focus_child(0), m_surface(0) {}; + virtual ~c_wnd() {}; + virtual int connect(c_wnd *parent, unsigned short resource_id, const char* str, + short x, short y, short width, short height, WND_TREE* p_child_tree = 0) + { + if (0 == resource_id) + { + ASSERT(false); + return -1; + } + m_id = resource_id; + set_str(str); + m_parent = parent; + m_status = STATUS_NORMAL; + if (parent) + { + m_z_order = parent->m_z_order; + m_surface = parent->m_surface; + } + if (0 == m_surface) + { + ASSERT(false); + return -2; + } + /* (cs.x = x * 1024 / 768) for 1027*768=>800*600 quickly*/ + m_wnd_rect.m_left = x; + m_wnd_rect.m_top = y; + m_wnd_rect.m_right = (x + width - 1); + m_wnd_rect.m_bottom = (y + height - 1); + pre_create_wnd(); + if (0 != parent) + { + parent->add_child_2_tail(this); + } + if (load_child_wnd(p_child_tree) >= 0) + { + on_init_children(); + } + return 0; + } + void disconnect() + { + if (0 == m_id) + { + return; + } + if (0 != m_top_child) + { + c_wnd* child = m_top_child; + c_wnd* next_child = 0; + while (child) + { + next_child = child->m_next_sibling; + child->disconnect(); + child = next_child; + } + } + if (0 != m_parent) + { + m_parent->unlink_child(this); + } + m_focus_child = 0; + m_id = 0; + } + virtual void on_init_children() {} + virtual void on_paint() {} + virtual void show_window() + { + if (ATTR_VISIBLE == (m_attr & ATTR_VISIBLE)) + { + on_paint(); + c_wnd* child = m_top_child; + if (0 != child) + { + while (child) + { + child->show_window(); + child = child->m_next_sibling; + } + } + } + } + unsigned short get_id() const { return m_id; } + int get_z_order() { return m_z_order; } + c_wnd* get_wnd_ptr(unsigned short id) const + { + c_wnd* child = m_top_child; + while (child) + { + if (child->get_id() == id) + { + break; + } + child = child->m_next_sibling; + } + return child; + } + unsigned int get_attr() const { return m_attr; } + void set_str(const char* str) { m_str = str; } + void set_attr(WND_ATTRIBUTION attr) { m_attr = attr; } + bool is_focus_wnd() const + { + return ((m_attr & ATTR_VISIBLE) && (m_attr & ATTR_FOCUS)) ? true : false; + } + void set_font_color(unsigned int color) { m_font_color = color; } + unsigned int get_font_color() { return m_font_color; } + void set_bg_color(unsigned int color) { m_bg_color = color; } + unsigned int get_bg_color() { return m_bg_color; } + void set_font_type(const LATTICE_FONT_INFO *font_type) { m_font = font_type; } + const void* get_font_type() { return m_font; } + void set_wnd_pos(short x, short y, short width, short height) + { + m_wnd_rect.m_left = x; + m_wnd_rect.m_top = y; + m_wnd_rect.m_right = x + width - 1; + m_wnd_rect.m_bottom = y + height - 1; + } + void get_wnd_rect(c_rect &rect) const { rect = m_wnd_rect; } + void get_screen_rect(c_rect &rect) const + { + int l = 0; + int t = 0; + wnd2screen(l, t); + rect.set_rect(l, t, m_wnd_rect.width(), m_wnd_rect.height()); + } + c_wnd* set_child_focus(c_wnd *focus_child) + { + ASSERT(0 != focus_child); + ASSERT(focus_child->m_parent == this); + c_wnd* old_focus_child = m_focus_child; + if (focus_child->is_focus_wnd()) + { + if (focus_child != old_focus_child) + { + if (old_focus_child) + { + old_focus_child->on_kill_focus(); + } + m_focus_child = focus_child; + m_focus_child->on_focus(); + } + } + return m_focus_child; + } + c_wnd* get_parent() const { return m_parent; } + c_wnd* get_last_child() const + { + if (0 == m_top_child) + { + return 0; + } + c_wnd* child = m_top_child; + while (child->m_next_sibling) + { + child = child->m_next_sibling; + } + return child; + } + int unlink_child(c_wnd *child) + { + if ((0 == child) + || (this != child->m_parent)) + { + return -1; + } + if (0 == m_top_child) + { + return -2; + } + bool find = false; + c_wnd* tmp_child = m_top_child; + if (tmp_child == child) + { + m_top_child = child->m_next_sibling; + if (0 != child->m_next_sibling) + { + child->m_next_sibling->m_prev_sibling = 0; + } + find = true; + } + else + { + while (tmp_child->m_next_sibling) + { + if (child == tmp_child->m_next_sibling) + { + tmp_child->m_next_sibling = child->m_next_sibling; + if (0 != child->m_next_sibling) + { + child->m_next_sibling->m_prev_sibling = tmp_child; + } + find = true; + break; + } + tmp_child = tmp_child->m_next_sibling; + } + } + if (true == find) + { + if (m_focus_child == child) + { + m_focus_child = 0; + } + child->m_next_sibling = 0; + child->m_prev_sibling = 0; + return 1; + } + else + { + return 0; + } + } + c_wnd* get_prev_sibling() const { return m_prev_sibling; } + c_wnd* get_next_sibling() const { return m_next_sibling; } + virtual void on_touch(int x, int y, TOUCH_ACTION action) + { + x -= m_wnd_rect.m_left; + y -= m_wnd_rect.m_top; + c_wnd* priority_wnd = 0; + c_wnd* tmp_child = m_top_child; + while (tmp_child) + { + if ((tmp_child->m_attr & ATTR_PRIORITY) && (tmp_child->m_attr & ATTR_VISIBLE)) + { + priority_wnd = tmp_child; + break; + } + tmp_child = tmp_child->m_next_sibling; + } + if (priority_wnd) + { + return priority_wnd->on_touch(x, y, action); + } + c_wnd* child = m_top_child; + while (child) + { + if (child->is_focus_wnd()) + { + c_rect rect; + child->get_wnd_rect(rect); + if (true == rect.pt_in_rect(x, y)) + { + return child->on_touch(x, y, action); + } + } + child = child->m_next_sibling; + } + } + virtual void on_navigate(NAVIGATION_KEY key) + { + c_wnd* priority_wnd = 0; + c_wnd* tmp_child = m_top_child; + while (tmp_child) + { + if ((tmp_child->m_attr & ATTR_PRIORITY) && (tmp_child->m_attr & ATTR_VISIBLE)) + { + priority_wnd = tmp_child; + break; + } + tmp_child = tmp_child->m_next_sibling; + } + if (priority_wnd) + { + return priority_wnd->on_navigate(key); + } + if (!is_focus_wnd()) + { + return; + } + if (key != NAV_BACKWARD && key != NAV_FORWARD) + { + if (m_focus_child) + { + m_focus_child->on_navigate(key); + } + return; + } + // Move focus + c_wnd* old_focus_wnd = m_focus_child; + // No current focus wnd, new one. + if (!old_focus_wnd) + { + c_wnd* child = m_top_child; + c_wnd* new_focus_wnd = 0; + while (child) + { + if (child->is_focus_wnd()) + { + new_focus_wnd = child; + new_focus_wnd->m_parent->set_child_focus(new_focus_wnd); + child = child->m_top_child; + continue; + } + child = child->m_next_sibling; + } + return; + } + // Move focus from old wnd to next wnd + c_wnd* next_focus_wnd = (key == NAV_FORWARD) ? old_focus_wnd->m_next_sibling : old_focus_wnd->m_prev_sibling; + while (next_focus_wnd && (!next_focus_wnd->is_focus_wnd())) + {// Search neighbor of old focus wnd + next_focus_wnd = (key == NAV_FORWARD) ? next_focus_wnd->m_next_sibling : next_focus_wnd->m_prev_sibling; + } + if (!next_focus_wnd) + {// Search whole brother wnd + next_focus_wnd = (key == NAV_FORWARD) ? old_focus_wnd->m_parent->m_top_child : old_focus_wnd->m_parent->get_last_child(); + while (next_focus_wnd && (!next_focus_wnd->is_focus_wnd())) + { + next_focus_wnd = (key == NAV_FORWARD) ? next_focus_wnd->m_next_sibling : next_focus_wnd->m_prev_sibling; + } + } + if (next_focus_wnd) + { + next_focus_wnd->m_parent->set_child_focus(next_focus_wnd); + } + } + c_surface* get_surface() { return m_surface; } + void set_surface(c_surface* surface) { m_surface = surface; } +protected: + virtual void pre_create_wnd() {}; + void add_child_2_tail(c_wnd *child) + { + if (0 == child)return; + if (child == get_wnd_ptr(child->m_id))return; + if (0 == m_top_child) + { + m_top_child = child; + child->m_prev_sibling = 0; + child->m_next_sibling = 0; + } + else + { + c_wnd* last_child = get_last_child(); + if (0 == last_child) + { + ASSERT(false); + } + last_child->m_next_sibling = child; + child->m_prev_sibling = last_child; + child->m_next_sibling = 0; + } + } + void wnd2screen(int &x, int &y) const + { + c_wnd* parent = m_parent; + c_rect rect; + x += m_wnd_rect.m_left; + y += m_wnd_rect.m_top; + while (0 != parent) + { + parent->get_wnd_rect(rect); + x += rect.m_left; + y += rect.m_top; + parent = parent->m_parent; + } + } + int load_child_wnd(WND_TREE *p_child_tree) + { + if (0 == p_child_tree) + { + return 0; + } + int sum = 0; + WND_TREE* p_cur = p_child_tree; + while (p_cur->p_wnd) + { + if (0 != p_cur->p_wnd->m_id) + {//This wnd has been used! Do not share! + ASSERT(false); + return -1; + } + else + { + p_cur->p_wnd->connect(this, p_cur->resource_id, p_cur->str, + p_cur->x, p_cur->y, p_cur->width, p_cur->height, p_cur->p_child_tree); + } + p_cur++; + sum++; + } + return sum; + } + void set_active_child(c_wnd* child) { m_focus_child = child; } + virtual void on_focus() {}; + virtual void on_kill_focus() {}; +protected: + unsigned short m_id; + WND_STATUS m_status; + WND_ATTRIBUTION m_attr; + c_rect m_wnd_rect; //position relative to parent window. + c_wnd* m_parent; //parent window + c_wnd* m_top_child; //the first sub window would be navigated + c_wnd* m_prev_sibling; //previous brother + c_wnd* m_next_sibling; //next brother + c_wnd* m_focus_child; //current focused window + const char* m_str; //caption + const void* m_font; //font face + unsigned int m_font_color; + unsigned int m_bg_color; + int m_z_order; //the graphic level for rendering + c_surface* m_surface; +}; +class c_button : public c_wnd +{ +public: + void set_on_click(WND_CALLBACK on_click) { this->on_click = on_click; } +protected: + virtual void on_paint() + { + c_rect rect; + get_screen_rect(rect); + switch (m_status) + { + case STATUS_NORMAL: + m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); + if (m_str) + { + c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); + } + break; + case STATUS_FOCUSED: + m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); + if (m_str) + { + c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); + } + break; + case STATUS_PUSHED: + m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_PUSHED), m_z_order); + m_surface->draw_rect(rect, c_theme::get_color(COLOR_WND_BORDER), 2, m_z_order); + if (m_str) + { + c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_PUSHED), ALIGN_HCENTER | ALIGN_VCENTER); + } + break; + default: + ASSERT(false); + break; + } + } + virtual void on_focus() + { + m_status = STATUS_FOCUSED; + on_paint(); + } + virtual void on_kill_focus() + { + m_status = STATUS_NORMAL; + on_paint(); + } + virtual void pre_create_wnd() + { + on_click = 0; + m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); + m_font = c_theme::get_font(FONT_DEFAULT); + m_font_color = c_theme::get_color(COLOR_WND_FONT); + } + virtual void on_touch(int x, int y, TOUCH_ACTION action) + { + if (action == TOUCH_DOWN) + { + m_parent->set_child_focus(this); + m_status = STATUS_PUSHED; + on_paint(); + } + else + { + m_status = STATUS_FOCUSED; + on_paint(); + if(on_click) + { + (m_parent->*(on_click))(m_id, 0); + } + } + } + virtual void on_navigate(NAVIGATION_KEY key) + { + switch (key) + { + case NAV_ENTER: + on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_DOWN); + on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_UP); + break; + case NAV_FORWARD: + case NAV_BACKWARD: + break; + } + return c_wnd::on_navigate(key); + } + WND_CALLBACK on_click; +}; +class c_surface; +class c_dialog; +typedef struct +{ + c_dialog* dialog; + c_surface* surface; +} DIALOG_ARRAY; +class c_dialog : public c_wnd +{ +public: + static int open_dialog(c_dialog* p_dlg, bool modal_mode = true) + { + if (0 == p_dlg) + { + ASSERT(false); + return 0; + } + c_dialog* cur_dlg = get_the_dialog(p_dlg->get_surface()); + if (cur_dlg == p_dlg) + { + return 1; + } + if (cur_dlg) + { + cur_dlg->set_attr(WND_ATTRIBUTION(0)); + } + p_dlg->set_attr(modal_mode ? (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY) : (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS)); + p_dlg->show_window(); + p_dlg->set_me_the_dialog(); + return 1; + } + static int close_dialog(c_surface* surface) + { + c_dialog* dlg = get_the_dialog(surface); + if (0 == dlg) + { + return 0; + } + c_rect rc; + dlg->get_screen_rect(rc); + dlg->set_attr(WND_ATTRIBUTION(0)); + surface->show_layer(rc, dlg->m_z_order - 1); + //clear the dialog + for (int i = 0; i < SURFACE_CNT_MAX; i++) + { + if (ms_the_dialogs[i].surface == surface) + { + ms_the_dialogs[i].dialog = 0; + return 1; + } + } + ASSERT(false); + return -1; + } + static c_dialog* get_the_dialog(c_surface* surface) + { + for (int i = 0; i < SURFACE_CNT_MAX; i++) + { + if (ms_the_dialogs[i].surface == surface) + { + return ms_the_dialogs[i].dialog; + } + } + return 0; + } +protected: + virtual void pre_create_wnd() + { + m_attr = WND_ATTRIBUTION(0);// no focus/visible + m_z_order = Z_ORDER_LEVEL_1; + m_bg_color = GL_RGB(33, 42, 53); + } + virtual void on_paint() + { + c_rect rect; + get_screen_rect(rect); + m_surface->fill_rect(rect, m_bg_color, m_z_order); + if (m_str) + { + c_word::draw_string(m_surface, m_z_order, m_str, rect.m_left + 35, rect.m_top, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_ARGB(0, 0, 0, 0)); + } + } +private: + int set_me_the_dialog() + { + c_surface* surface = get_surface(); + for (int i = 0; i < SURFACE_CNT_MAX; i++) + { + if (ms_the_dialogs[i].surface == surface) + { + ms_the_dialogs[i].dialog = this; + return 0; + } + } + for (int i = 0; i < SURFACE_CNT_MAX; i++) + { + if (ms_the_dialogs[i].surface == 0) + { + ms_the_dialogs[i].dialog = this; + ms_the_dialogs[i].surface = surface; + return 1; + } + } + ASSERT(false); + return -2; + } + static DIALOG_ARRAY ms_the_dialogs[SURFACE_CNT_MAX]; +}; +#include +//Changing key width/height will change the width/height of keyboard +#define KEY_WIDTH 65 +#define KEY_HEIGHT 38 +#define KEYBOARD_WIDTH ((KEY_WIDTH + 2) * 10) +#define KEYBOARD_HEIGHT ((KEY_HEIGHT + 2) * 4) +#define NUM_BOARD_WIDTH ((KEY_WIDTH + 2) * 4) +#define NUM_BOARD_HEIGHT ((KEY_HEIGHT + 2) * 4) +#define CAPS_WIDTH (KEY_WIDTH * 3 / 2) +#define DEL_WIDTH (KEY_WIDTH * 3 / 2 + 1) +#define ESC_WIDTH (KEY_WIDTH * 2 + 2) +#define SWITCH_WIDTH (KEY_WIDTH * 3 / 2 ) +#define SPACE_WIDTH (KEY_WIDTH * 3 + 2 * 2) +#define DOT_WIDTH (KEY_WIDTH * 3 / 2 + 3) +#define ENTER_WIDTH (KEY_WIDTH * 2 + 2) +#define POS_X(c) ((KEY_WIDTH * c) + (c + 1) * 2) +#define POS_Y(r) ((KEY_HEIGHT * r) + (r + 1) * 2) +#define KEYBORAD_CLICK 0x5014 +#define ON_KEYBORAD_UPDATE(func) \ +{MSG_TYPE_WND, KEYBORAD_CLICK, 0, msgCallback(&func)}, +typedef enum +{ + STATUS_UPPERCASE, + STATUS_LOWERCASE +}KEYBOARD_STATUS; +typedef enum +{ + STYLE_ALL_BOARD, + STYLE_NUM_BOARD +}KEYBOARD_STYLE; +typedef enum +{ + CLICK_CHAR, + CLICK_ENTER, + CLICK_ESC +}CLICK_STATUS; +extern WND_TREE g_key_board_children[]; +extern WND_TREE g_number_board_children[]; +class c_keyboard: public c_wnd +{ +public: + virtual int connect(c_wnd *user, unsigned short resource_id, KEYBOARD_STYLE style) + { + c_rect user_rect; + user->get_wnd_rect(user_rect); + if (style == STYLE_ALL_BOARD) + {//Place keyboard at the bottom of user's parent window. + c_rect user_parent_rect; + user->get_parent()->get_wnd_rect(user_parent_rect); + return c_wnd::connect(user, resource_id, 0, (0 - user_rect.m_left), (user_parent_rect.height() - user_rect.m_top - KEYBOARD_HEIGHT - 1), KEYBOARD_WIDTH, KEYBOARD_HEIGHT, g_key_board_children); + } + else if (style == STYLE_NUM_BOARD) + {//Place keyboard below the user window. + return c_wnd::connect(user, resource_id, 0, 0, user_rect.height(), NUM_BOARD_WIDTH, NUM_BOARD_HEIGHT, g_number_board_children); + } + else + { + ASSERT(false); + } + return -1; + } + virtual void on_init_children() + { + c_wnd* child = m_top_child; + if (0 != child) + { + while (child) + { + ((c_button*)child)->set_on_click(WND_CALLBACK(&c_keyboard::on_key_clicked)); + child = child->get_next_sibling(); + } + } + } + KEYBOARD_STATUS get_cap_status(){return m_cap_status;} + char* get_str() { return m_str; } + void set_on_click(WND_CALLBACK on_click) { this->on_click = on_click; } +protected: + virtual void pre_create_wnd() + { + m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); + m_cap_status = STATUS_UPPERCASE; + memset(m_str, 0, sizeof(m_str)); + m_str_len = 0; + } + virtual void on_paint() + { + c_rect rect; + get_screen_rect(rect); + m_surface->fill_rect(rect, GL_RGB(0, 0, 0), m_z_order); + } + void on_key_clicked(int id, int param) + { + switch (id) + { + case 0x14: + on_caps_clicked(id, param); + break; + case '\n': + on_enter_clicked(id, param); + break; + case 0x1B: + on_esc_clicked(id, param); + break; + case 0x7F: + on_del_clicked(id, param); + break; + default: + on_char_clicked(id, param); + break; + } + } + void on_char_clicked(int id, int param) + {//id = char ascii code. + if (m_str_len >= sizeof(m_str)) + { + return; + } + if ((id >= '0' && id <= '9') || id == ' ' || id == '.') + { + goto InputChar; + } + if (id >= 'A' && id <= 'Z') + { + if (STATUS_LOWERCASE == m_cap_status) + { + id += 0x20; + } + goto InputChar; + } + ASSERT(false); + InputChar: + m_str[m_str_len++] = id; + (m_parent->*(on_click))(m_id, CLICK_CHAR); + } + void on_del_clicked(int id, int param) + { + if (m_str_len <= 0) + { + return; + } + m_str[--m_str_len] = 0; + (m_parent->*(on_click))(m_id, CLICK_CHAR); + } + void on_caps_clicked(int id, int param) + { + m_cap_status = (m_cap_status == STATUS_LOWERCASE) ? STATUS_UPPERCASE : STATUS_LOWERCASE; + show_window(); + } + void on_enter_clicked(int id, int param) + { + memset(m_str, 0, sizeof(m_str)); + (m_parent->*(on_click))(m_id, CLICK_ENTER); + } + void on_esc_clicked(int id, int param) + { + memset(m_str, 0, sizeof(m_str)); + (m_parent->*(on_click))(m_id, CLICK_ESC); + } +private: + char m_str[32]; + int m_str_len; + KEYBOARD_STATUS m_cap_status; + WND_CALLBACK on_click; +}; +class c_keyboard_button : public c_button +{ +protected: + virtual void on_paint() + { + c_rect rect; + get_screen_rect(rect); + switch (m_status) + { + case STATUS_NORMAL: + m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); + break; + case STATUS_FOCUSED: + m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); + break; + case STATUS_PUSHED: + m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_PUSHED), m_z_order); + m_surface->draw_rect(rect, c_theme::get_color(COLOR_WND_BORDER), 2, m_z_order); + break; + default: + ASSERT(false); + break; + } + if (m_id == 0x14) + { + return c_word::draw_string_in_rect(m_surface, m_z_order, "Caps", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); + } + else if (m_id == 0x1B) + { + return c_word::draw_string_in_rect(m_surface, m_z_order, "Esc", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); + } + else if (m_id == ' ') + { + return c_word::draw_string_in_rect(m_surface, m_z_order, "Space", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); + } + else if (m_id == '\n') + { + return c_word::draw_string_in_rect(m_surface, m_z_order, "Enter", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); + } + else if (m_id == '.') + { + return c_word::draw_string_in_rect(m_surface, m_z_order, ".", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); + } + else if (m_id == 0x7F) + { + return c_word::draw_string_in_rect(m_surface, m_z_order, "Back", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); + } + else if (m_id == 0x90) + { + return c_word::draw_string_in_rect(m_surface, m_z_order, "?123", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); + } + char letter[] = { 0, 0 }; + if (m_id >= 'A' && m_id <= 'Z') + { + letter[0] = (((c_keyboard*)m_parent)->get_cap_status() == STATUS_UPPERCASE) ? m_id : (m_id + 0x20); + } + else if (m_id >= '0' && m_id <= '9') + { + letter[0] = (char)m_id; + } + c_word::draw_string_in_rect(m_surface, m_z_order, letter, rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); + } +}; +#include +#define MAX_EDIT_STRLEN 32 +#define IDD_KEY_BOARD 0x1 +class c_edit : public c_wnd +{ + friend class c_keyboard; +public: + const char* get_text(){return m_str;} + void set_text(const char* str) + { + if (str != 0 && strlen(str) < sizeof(m_str)) + { + strcpy(m_str, str); + } + } + void set_keyboard_style(KEYBOARD_STYLE kb_sytle) { m_kb_style = kb_sytle; } + +protected: + virtual void pre_create_wnd() + { + m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); + m_kb_style = STYLE_ALL_BOARD; + m_font = c_theme::get_font(FONT_DEFAULT); + m_font_color = c_theme::get_color(COLOR_WND_FONT); + memset(m_str_input, 0, sizeof(m_str_input)); + memset(m_str, 0, sizeof(m_str)); + set_text(c_wnd::m_str); + } + virtual void on_paint() + { + c_rect rect, kb_rect; + get_screen_rect(rect); + s_keyboard.get_screen_rect(kb_rect); + switch (m_status) + { + case STATUS_NORMAL: + if (m_z_order > m_parent->get_z_order()) + { + s_keyboard.disconnect(); + m_z_order = m_parent->get_z_order(); + m_surface->show_layer(kb_rect, m_z_order); + m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); + } + m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); + c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); + break; + case STATUS_FOCUSED: + if (m_z_order > m_parent->get_z_order()) + { + s_keyboard.disconnect(); + m_z_order = m_parent->get_z_order(); + m_surface->show_layer(kb_rect, m_z_order); + m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); + } + m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); + c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); + break; + case STATUS_PUSHED: + if (m_z_order == m_parent->get_z_order()) + { + m_z_order++; + m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY); + show_keyboard(); + } + m_surface->fill_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, c_theme::get_color(COLOR_WND_PUSHED), m_parent->get_z_order()); + m_surface->draw_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, c_theme::get_color(COLOR_WND_BORDER), m_parent->get_z_order(), 2); + strlen(m_str_input) ? c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str_input, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_PUSHED), ALIGN_HCENTER | ALIGN_VCENTER) : + c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_PUSHED), ALIGN_HCENTER | ALIGN_VCENTER); + break; + default: + ASSERT(false); + } + } + virtual void on_focus() + { + m_status = STATUS_FOCUSED; + on_paint(); + } + virtual void on_kill_focus() + { + m_status = STATUS_NORMAL; + on_paint(); + } + virtual void on_navigate(NAVIGATION_KEY key) + { + switch (key) + { + case NAV_ENTER: + (m_status == STATUS_PUSHED) ? s_keyboard.on_navigate(key) : (on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_DOWN), on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_UP)); + return; + case NAV_BACKWARD: + case NAV_FORWARD: + return (m_status == STATUS_PUSHED) ? s_keyboard.on_navigate(key) : c_wnd::on_navigate(key); + } + } + virtual void on_touch(int x, int y, TOUCH_ACTION action) + { + (action == TOUCH_DOWN) ? on_touch_down(x, y) : on_touch_up(x, y); + } + void on_key_board_click(int id, int param) + { + switch (param) + { + case CLICK_CHAR: + strcpy(m_str_input, s_keyboard.get_str()); + on_paint(); + break; + case CLICK_ENTER: + if (strlen(m_str_input)) + { + memcpy(m_str, m_str_input, sizeof(m_str_input)); + } + m_status = STATUS_FOCUSED; + on_paint(); + break; + case CLICK_ESC: + memset(m_str_input, 0, sizeof(m_str_input)); + m_status = STATUS_FOCUSED; + on_paint(); + break; + default: + ASSERT(false); + break; + } + } +private: + void show_keyboard() + { + s_keyboard.connect(this, IDD_KEY_BOARD, m_kb_style); + s_keyboard.set_on_click(WND_CALLBACK(&c_edit::on_key_board_click)); + s_keyboard.show_window(); + } + void on_touch_down(int x, int y) + { + c_rect kb_rect_relate_2_edit_parent; + s_keyboard.get_wnd_rect(kb_rect_relate_2_edit_parent); + kb_rect_relate_2_edit_parent.m_left += m_wnd_rect.m_left; + kb_rect_relate_2_edit_parent.m_right += m_wnd_rect.m_left; + kb_rect_relate_2_edit_parent.m_top += m_wnd_rect.m_top; + kb_rect_relate_2_edit_parent.m_bottom += m_wnd_rect.m_top; + if (m_wnd_rect.pt_in_rect(x, y)) + {//click edit box + if (STATUS_NORMAL == m_status) + { + m_parent->set_child_focus(this); + } + } + else if (kb_rect_relate_2_edit_parent.pt_in_rect(x, y)) + {//click key board + c_wnd::on_touch(x, y, TOUCH_DOWN); + } + else + { + if (STATUS_PUSHED == m_status) + { + m_status = STATUS_FOCUSED; + on_paint(); + } + } + } + void on_touch_up(int x, int y) + { + if (STATUS_FOCUSED == m_status) + { + m_status = STATUS_PUSHED; + on_paint(); + } + else if (STATUS_PUSHED == m_status) + { + if (m_wnd_rect.pt_in_rect(x, y)) + {//click edit box + m_status = STATUS_FOCUSED; + on_paint(); + } + else + { + c_wnd::on_touch(x, y, TOUCH_UP); + } + } + } + static c_keyboard s_keyboard; + KEYBOARD_STYLE m_kb_style; + char m_str_input[MAX_EDIT_STRLEN]; + char m_str[MAX_EDIT_STRLEN]; +}; +class c_label : public c_wnd +{ +public: + virtual void on_paint() + { + c_rect rect; + unsigned int bg_color = m_bg_color ? m_bg_color : m_parent->get_bg_color(); + get_screen_rect(rect); + if (m_str) + { + m_surface->fill_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, bg_color, m_z_order); + c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, bg_color, ALIGN_LEFT | ALIGN_VCENTER); + } + } +protected: + virtual void pre_create_wnd() + { + m_attr = ATTR_VISIBLE; + m_font_color = c_theme::get_color(COLOR_WND_FONT); + m_font = c_theme::get_font(FONT_DEFAULT); + } +}; +#include +#define MAX_ITEM_NUM 4 +#define ITEM_HEIGHT 45 +class c_list_box : public c_wnd +{ +public: + void set_on_change(WND_CALLBACK on_change) { this->on_change = on_change; } + short get_item_count() { return m_item_total; } + int add_item(char* str) + { + if (m_item_total >= MAX_ITEM_NUM) + { + ASSERT(false); + return -1; + } + m_item_array[m_item_total++] = str; + update_list_size(); + return 0; + } + void clear_item() + { + m_selected_item = m_item_total = 0; + memset(m_item_array, 0, sizeof(m_item_array)); + update_list_size(); + } + void select_item(short index) + { + if (index < 0 || index >= m_item_total) + { + ASSERT(false); + } + m_selected_item = index; + } + +protected: + virtual void pre_create_wnd() + { + m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); + memset(m_item_array, 0, sizeof(m_item_array)); + m_item_total = 0; + m_selected_item = 0; + m_font = c_theme::get_font(FONT_DEFAULT); + m_font_color = c_theme::get_color(COLOR_WND_FONT); + } + virtual void on_paint() + { + c_rect rect; + get_screen_rect(rect); + switch (m_status) + { + case STATUS_NORMAL: + if (m_z_order > m_parent->get_z_order()) + { + m_z_order = m_parent->get_z_order(); + m_surface->show_layer(m_list_screen_rect, m_z_order); + m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); + } + m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); + c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[m_selected_item], rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); + break; + case STATUS_FOCUSED: + if (m_z_order > m_parent->get_z_order()) + { + m_z_order = m_parent->get_z_order(); + m_surface->show_layer(m_list_screen_rect, m_z_order); + m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); + } + m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); + c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[m_selected_item], rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); + break; + case STATUS_PUSHED: + m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_PUSHED), m_z_order); + m_surface->draw_rect(rect, c_theme::get_color(COLOR_WND_BORDER), 2, m_z_order); + c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[m_selected_item], rect, m_font, GL_RGB(2, 124, 165), GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER | ALIGN_VCENTER); + //draw list + if (m_item_total > 0) + { + if (m_z_order == m_parent->get_z_order()) + { + m_z_order++; + } + m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY); + show_list(); + } + break; + default: + ASSERT(false); + } + } + virtual void on_focus() + { + m_status = STATUS_FOCUSED; + on_paint(); + } + virtual void on_kill_focus() + { + m_status = STATUS_NORMAL; + on_paint(); + } + virtual void on_navigate(NAVIGATION_KEY key) + { + switch (key) + { + case NAV_ENTER: + on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_DOWN); + on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_UP); + return; + case NAV_BACKWARD: + if (m_status != STATUS_PUSHED) + { + return c_wnd::on_navigate(key); + } + m_selected_item = (m_selected_item > 0) ? (m_selected_item - 1) : m_selected_item; + return show_list(); + case NAV_FORWARD: + if (m_status != STATUS_PUSHED) + { + return c_wnd::on_navigate(key); + } + m_selected_item = (m_selected_item < (m_item_total - 1)) ? (m_selected_item + 1) : m_selected_item; + return show_list(); + } + } + virtual void on_touch(int x, int y, TOUCH_ACTION action) + { + (action == TOUCH_DOWN) ? on_touch_down(x, y) : on_touch_up(x, y); + } + +private: + void update_list_size() + { + m_list_wnd_rect = m_wnd_rect; + m_list_wnd_rect.m_top = m_wnd_rect.m_bottom + 1; + m_list_wnd_rect.m_bottom = m_list_wnd_rect.m_top + m_item_total * ITEM_HEIGHT; + get_screen_rect(m_list_screen_rect); + m_list_screen_rect.m_top = m_list_screen_rect.m_bottom + 1; + m_list_screen_rect.m_bottom = m_list_screen_rect.m_top + m_item_total * ITEM_HEIGHT; + } + void show_list() + { + //draw all items + c_rect tmp_rect; + for (int i = 0; i < m_item_total; i++) + { + tmp_rect.m_left = m_list_screen_rect.m_left; + tmp_rect.m_right = m_list_screen_rect.m_right; + tmp_rect.m_top = m_list_screen_rect.m_top + i * ITEM_HEIGHT; + tmp_rect.m_bottom = tmp_rect.m_top + ITEM_HEIGHT; + if (m_selected_item == i) + { + m_surface->fill_rect(tmp_rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); + c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[i], tmp_rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); + } + else + { + m_surface->fill_rect(tmp_rect, GL_RGB(17, 17, 17), m_z_order); + c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[i], tmp_rect, m_font, m_font_color, GL_RGB(17, 17, 17), ALIGN_HCENTER | ALIGN_VCENTER); + } + } + } + void on_touch_down(int x, int y) + { + if (m_wnd_rect.pt_in_rect(x, y)) + {//click base + if (STATUS_NORMAL == m_status) + { + m_parent->set_child_focus(this); + } + } + else if (m_list_wnd_rect.pt_in_rect(x, y)) + {//click extend list + c_wnd::on_touch(x, y, TOUCH_DOWN); + } + else + { + if (STATUS_PUSHED == m_status) + { + m_status = STATUS_FOCUSED; + on_paint(); + if(on_change) + { + (m_parent->*(on_change))(m_id, m_selected_item); + } + } + } + } + void on_touch_up(int x, int y) + { + if (STATUS_FOCUSED == m_status) + { + m_status = STATUS_PUSHED; + on_paint(); + } + else if (STATUS_PUSHED == m_status) + { + if (m_wnd_rect.pt_in_rect(x, y)) + {//click base + m_status = STATUS_FOCUSED; + on_paint(); + } + else if (m_list_wnd_rect.pt_in_rect(x, y)) + {//click extend list + m_status = STATUS_FOCUSED; + select_item((y - m_list_wnd_rect.m_top) / ITEM_HEIGHT); + on_paint(); + if(on_change) + { + (m_parent->*(on_change))(m_id, m_selected_item); + } + } + else + { + c_wnd::on_touch(x, y, TOUCH_UP); + } + } + } + short m_selected_item; + short m_item_total; + char* m_item_array[MAX_ITEM_NUM]; + c_rect m_list_wnd_rect; //rect relative to parent wnd. + c_rect m_list_screen_rect; //rect relative to physical screen(frame buffer) + WND_CALLBACK on_change; +}; +#include +#define MAX_PAGES 5 +class c_gesture; +class c_slide_group : public c_wnd { +public: + inline c_slide_group(); + int set_active_slide(int index, bool is_redraw = true) + { + if (index >= MAX_PAGES || index < 0) + { + return -1; + } + if (0 == m_slides[index]) + { + return -2; + } + m_active_slide_index = index; + for (int i = 0; i < MAX_PAGES; i++) + { + if (m_slides[i] == 0) + { + continue; + } + if (i == index) + { + m_slides[i]->get_surface()->set_active(true); + add_child_2_tail(m_slides[i]); + if (is_redraw) + { + c_rect rc; + get_screen_rect(rc); + m_slides[i]->get_surface()->flush_screen(rc.m_left, rc.m_top, rc.m_right, rc.m_bottom); + } + } + else + { + m_slides[i]->get_surface()->set_active(false); + } + } + return 0; + } + c_wnd* get_slide(int index){return m_slides[index];} + c_wnd* get_active_slide(){return m_slides[m_active_slide_index];} + int get_active_slide_index(){return m_active_slide_index;} + int add_slide(c_wnd* slide, unsigned short resource_id, short x, short y, short width, short height, WND_TREE* p_child_tree = 0, Z_ORDER_LEVEL max_zorder = Z_ORDER_LEVEL_0) + { + if (0 == slide) + { + return -1; + } + c_surface* old_surface = get_surface(); + c_surface* new_surface = old_surface->get_display()->alloc_surface(max_zorder); + new_surface->set_active(false); + set_surface(new_surface); + slide->connect(this, resource_id, 0, x, y, width, height, p_child_tree); + set_surface(old_surface); + int i = 0; + while (i < MAX_PAGES) + { + if (m_slides[i] == slide) + {//slide has lived + ASSERT(false); + return -2; + } + i++; + } + //new slide + i = 0; + while (i < MAX_PAGES) + { + if (m_slides[i] == 0) + { + m_slides[i] = slide; + slide->show_window(); + return 0; + } + i++; + } + //no more slide can be add + ASSERT(false); + return -3; + } + void disabel_all_slide() + { + for (int i = 0; i < MAX_PAGES; i++) + { + if (m_slides[i]) + { + m_slides[i]->get_surface()->set_active(false); + } + } + } + inline virtual void on_touch(int x, int y, TOUCH_ACTION action); + virtual void on_navigate(NAVIGATION_KEY key) + { + if (m_slides[m_active_slide_index]) + { + m_slides[m_active_slide_index]->on_navigate(key); + } + } +protected: + c_wnd* m_slides[MAX_PAGES]; + int m_active_slide_index; + c_gesture* m_gesture; +}; +//#define SWIPE_STEP 300//for arm +#define SWIPE_STEP 10//for PC & ANDROID +#define MOVE_THRESHOLD 10 +typedef enum { + TOUCH_MOVE, + TOUCH_IDLE +}TOUCH_STATE; +class c_slide_group; +class c_gesture { +public: + c_gesture(c_slide_group* group) + { + m_slide_group = group; + m_state = TOUCH_IDLE; + m_down_x = m_down_y = m_move_x = m_move_y = 0; + } + bool handle_swipe(int x, int y, TOUCH_ACTION action) + { + if (action == TOUCH_DOWN)//MOUSE_LBUTTONDOWN + { + if (m_state == TOUCH_IDLE) + { + m_state = TOUCH_MOVE; + m_move_x = m_down_x = x; + return true; + } + else//TOUCH_MOVE + { + return on_move(x); + } + } + else if (action == TOUCH_UP)//MOUSE_LBUTTONUP + { + if (m_state == TOUCH_MOVE) + { + m_state = TOUCH_IDLE; + return on_swipe(x); + } + else + { + return false; + //ASSERT(false); + } + } + return true; + } +private: + bool on_move(int x) + { + if (m_slide_group == 0) + { + return true; + } + if (abs(x - m_move_x) < MOVE_THRESHOLD) + { + return false; + } + m_slide_group->disabel_all_slide(); + m_move_x = x; + if ((m_move_x - m_down_x) > 0) + { + move_right(); + } + else + { + move_left(); + } + return false; + } + bool on_swipe(int x) + { + if (m_slide_group == 0) + { + return true; + } + if ((m_down_x == m_move_x) && (abs(x - m_down_x) < MOVE_THRESHOLD)) + { + return true; + } + m_slide_group->disabel_all_slide(); + int page = -1; + m_move_x = x; + if ((m_move_x - m_down_x) > 0) + { + page = swipe_right(); + } + else + { + page = swipe_left(); + } + if (page >= 0) + { + m_slide_group->set_active_slide(page); + } + else + { + m_slide_group->set_active_slide(m_slide_group->get_active_slide_index(), false); + } + return false; + } + int swipe_left() + { + if (m_slide_group == 0) + { + return -1; + } + int index = m_slide_group->get_active_slide_index(); + if ((index + 1) >= MAX_PAGES || + m_slide_group->get_slide(index + 1) == 0 || + m_slide_group->get_slide(index) == 0) + { + return -2; + } + c_surface* s1 = m_slide_group->get_slide(index + 1)->get_surface(); + c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); + if (s1->get_display() != s2->get_display()) + { + return -3; + } + int step = m_down_x - m_move_x; + c_rect rc; + m_slide_group->get_screen_rect(rc); + while (step < rc.width()) + { + s1->get_display()->swipe_surface(s2, s1, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, step); + step += SWIPE_STEP; + } + if (step != rc.width()) + { + s1->get_display()->swipe_surface(s2, s1, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, rc.width()); + } + return (index + 1); + } + int swipe_right() + { + if (m_slide_group == 0) + { + return -1; + } + int index = m_slide_group->get_active_slide_index(); + if (index <= 0 || + m_slide_group->get_slide(index - 1) == 0 || + m_slide_group->get_slide(index) == 0) + { + return -2; + } + c_surface* s1 = m_slide_group->get_slide(index - 1)->get_surface(); + c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); + if (s1->get_display() != s2->get_display()) + { + return -3; + } + c_rect rc; + m_slide_group->get_screen_rect(rc); + int step = rc.width() - (m_move_x - m_down_x); + while (step > 0) + { + s1->get_display()->swipe_surface(s1, s2, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, step); + step -= SWIPE_STEP; + } + if (step != 0) + { + s1->get_display()->swipe_surface(s1, s2, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, 0); + } + return (index - 1); + } + void move_left() + { + int index = m_slide_group->get_active_slide_index(); + if ((index + 1) >= MAX_PAGES || + m_slide_group->get_slide(index + 1) == 0 || + m_slide_group->get_slide(index) == 0) + { + return; + } + c_surface* s1 = m_slide_group->get_slide(index + 1)->get_surface(); + c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); + c_rect rc; + m_slide_group->get_screen_rect(rc); + if (s1->get_display() == s2->get_display()) + { + s1->get_display()->swipe_surface(s2, s1, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, (m_down_x - m_move_x)); + } + } + void move_right() + { + int index = m_slide_group->get_active_slide_index(); + if (index <= 0 || + m_slide_group->get_slide(index - 1) == 0 || + m_slide_group->get_slide(index) == 0) + { + return; + } + c_surface* s1 = m_slide_group->get_slide(index - 1)->get_surface(); + c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); + c_rect rc; + m_slide_group->get_screen_rect(rc); + if (s1->get_display() == s2->get_display()) + { + s1->get_display()->swipe_surface(s1, s2, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, (rc.width() - (m_move_x - m_down_x))); + } + } + int m_down_x; + int m_down_y; + int m_move_x; + int m_move_y; + TOUCH_STATE m_state; + c_slide_group* m_slide_group; +}; +inline c_slide_group::c_slide_group() +{ + m_gesture = new c_gesture(this); + for (int i = 0; i < MAX_PAGES; i++) + { + m_slides[i] = 0; + } + m_active_slide_index = 0; +} +inline void c_slide_group::on_touch(int x, int y, TOUCH_ACTION action) +{ + x -= m_wnd_rect.m_left; + y -= m_wnd_rect.m_top; + if (m_gesture->handle_swipe(x, y, action)) + { + if (m_slides[m_active_slide_index]) + { + m_slides[m_active_slide_index]->on_touch(x, y, action); + } + } +} +#define ID_BT_ARROW_UP 0x1111 +#define ID_BT_ARROW_DOWN 0x2222 +class c_spin_box; +class c_spin_button : public c_button +{ + friend class c_spin_box; + inline virtual void on_touch(int x, int y, TOUCH_ACTION action); + c_spin_box* m_spin_box; +}; +class c_spin_box : public c_wnd +{ + friend class c_spin_button; +public: + short get_value() { return m_value; } + void set_value(unsigned short value) { m_value = m_cur_value = value; } + void set_max_min(short max, short min) { m_max = max; m_min = min; } + void set_step(short step) { m_step = step; } + short get_min() { return m_min; } + short get_max() { return m_max; } + short get_step() { return m_step; } + void set_value_digit(short digit) { m_digit = digit; } + short get_value_digit() { return m_digit; } + void set_on_change(WND_CALLBACK on_change) { this->on_change = on_change; } +protected: + virtual void on_paint() + { + c_rect rect; + get_screen_rect(rect); + rect.m_right = rect.m_left + (rect.width() * 2 / 3); + m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); + c_word::draw_value_in_rect(m_surface, m_parent->get_z_order(), m_cur_value, m_digit, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); + } + virtual void pre_create_wnd() + { + m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE); + m_font = c_theme::get_font(FONT_DEFAULT); + m_font_color = c_theme::get_color(COLOR_WND_FONT); + m_max = 6; + m_min = 1; + m_digit = 0; + m_step = 1; + //link arrow button position. + c_rect rect; + get_wnd_rect(rect); + m_bt_down.m_spin_box = m_bt_up.m_spin_box = this; + m_bt_up.connect(m_parent, ID_BT_ARROW_UP, "+", (rect.m_left + rect.width() * 2 / 3), rect.m_top, (rect.width() / 3), (rect.height() / 2)); + m_bt_down.connect(m_parent, ID_BT_ARROW_DOWN, "-", (rect.m_left + rect.width() * 2 / 3), (rect.m_top + rect.height() / 2), (rect.width() / 3), (rect.height() / 2)); + } + void on_arrow_up_bt_click() + { + if (m_cur_value + m_step > m_max) + { + return; + } + m_cur_value += m_step; + if(on_change) + { + (m_parent->*(on_change))(m_id, m_cur_value); + } + on_paint(); + } + void on_arrow_down_bt_click() + { + if (m_cur_value - m_step < m_min) + { + return; + } + m_cur_value -= m_step; + if(on_change) + { + (m_parent->*(on_change))(m_id, m_cur_value); + } + on_paint(); + } + short m_cur_value; + short m_value; + short m_step; + short m_max; + short m_min; + short m_digit; + c_spin_button m_bt_up; + c_spin_button m_bt_down; + WND_CALLBACK on_change; +}; +inline void c_spin_button::on_touch(int x, int y, TOUCH_ACTION action) +{ + if (action == TOUCH_UP) + { + (m_id == ID_BT_ARROW_UP) ? m_spin_box->on_arrow_up_bt_click() : m_spin_box->on_arrow_down_bt_click(); + } + c_button::on_touch(x, y, action); +} +#define MAX_COL_NUM 30 +#define MAX_ROW_NUM 30 +class c_table: public c_wnd +{ +public: + void set_sheet_align(unsigned int align_type){ m_align_type = align_type;} + void set_row_num(unsigned int row_num){ m_row_num = row_num;} + void set_col_num(unsigned int col_num){ m_col_num = col_num;} + void set_row_height(unsigned int height) + { + for (unsigned int i = 0; i < m_row_num; i++) + { + m_row_height[i] = height; + } + } + void set_col_width(unsigned int width) + { + for (unsigned int i = 0; i < m_col_num; i++) + { + m_col_width[i] = width; + } + } + int set_row_height(unsigned int index, unsigned int height) + { + if (m_row_num > index) + { + m_row_height[index] = height; + return index; + } + return -1; + } + int set_col_width(unsigned int index, unsigned int width) + { + if (m_col_num > index) + { + m_col_width[index] = width; + return index; + } + return -1; + } + void set_item(int row, int col, char* str, unsigned int color) + { + draw_item(row, col, str, color); + } + unsigned int get_row_num(){ return m_row_num;} + unsigned int get_col_num(){ return m_col_num;} + c_rect get_item_rect(int row, int col) + { + static c_rect rect; + if (row >= MAX_ROW_NUM || col >= MAX_COL_NUM) + { + return rect; + } + unsigned int width = 0; + unsigned int height = 0; + for (int i = 0; i < col; i++) + { + width += m_col_width[i]; + } + for (int j = 0; j < row; j++) + { + height += m_row_height[j]; + } + c_rect wRect; + get_screen_rect(wRect); + rect.m_left = wRect.m_left + width; + rect.m_right = rect.m_left + m_col_width[col]; + if (rect.m_right > wRect.m_right) + { + rect.m_right = wRect.m_right; + } + rect.m_top = wRect.m_top + height; + rect.m_bottom = rect.m_top + m_row_height[row]; + if (rect.m_bottom > wRect.m_bottom) + { + rect.m_bottom = wRect.m_bottom; + } + return rect; + } +protected: + virtual void pre_create_wnd() + { + m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE); + m_font = c_theme::get_font(FONT_DEFAULT); + m_font_color = c_theme::get_color(COLOR_WND_FONT); + } + void draw_item(int row, int col, const char* str, unsigned int color) + { + c_rect rect = get_item_rect(row, col); + m_surface->fill_rect(rect.m_left + 1, rect.m_top + 1, rect.m_right - 1, rect.m_bottom - 1, color, m_z_order); + c_word::draw_string_in_rect(m_surface, m_z_order, str, rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_align_type); + } + unsigned int m_align_type; + unsigned int m_row_num; + unsigned int m_col_num; + unsigned int m_row_height[MAX_ROW_NUM]; + unsigned int m_col_width[MAX_COL_NUM]; +}; +#include +#include +#define WAVE_BUFFER_LEN 1024 +#define WAVE_READ_CACHE_LEN 8 +#define BUFFER_EMPTY -1111 +#define BUFFER_FULL -2222; +class c_wave_buffer +{ +public: + c_wave_buffer() + { + m_head = m_tail = m_min_old = m_max_old = + m_min_older = m_max_older = m_last_data = m_read_cache_sum = m_refresh_sequence = 0; + memset(m_wave_buf, 0, sizeof(m_wave_buf)); + memset(m_read_cache_min, 0, sizeof(m_read_cache_min)); + memset(m_read_cache_mid, 0, sizeof(m_read_cache_mid)); + memset(m_read_cache_max, 0, sizeof(m_read_cache_max)); + } + int write_wave_data(short data) + { + if ((m_tail + 1) % WAVE_BUFFER_LEN == m_head) + {//full + //log_out("wave buf full\n"); + return BUFFER_FULL; + } + m_wave_buf[m_tail] = data; + m_tail = (m_tail + 1) % WAVE_BUFFER_LEN; + return 1; + } + int read_wave_data_by_frame(short &max, short &min, short frame_len, unsigned int sequence, short offset) + { + if (m_refresh_sequence != sequence) + { + m_refresh_sequence = sequence; + m_read_cache_sum = 0; + } + else if (offset < m_read_cache_sum)//(m_refresh_sequence == sequence && offset < m_fb_sum) + { + max = m_read_cache_max[offset]; + min = m_read_cache_min[offset]; + return m_read_cache_mid[offset]; + } + m_read_cache_sum++; + ASSERT(m_read_cache_sum <= WAVE_READ_CACHE_LEN); + int i, data; + int tmp_min = m_last_data; + int tmp_max = m_last_data; + int mid = (m_min_old + m_max_old) >> 1; + i = 0; + while (i++ < frame_len) + { + data = read_data(); + if (BUFFER_EMPTY == data) + { + break; + } + m_last_data = data; + if (data < tmp_min) { tmp_min = data; } + if (data > tmp_max) { tmp_max = data; } + } + min = m_read_cache_min[offset] = MIN(m_min_old, MIN(tmp_min, m_min_older)); + max = m_read_cache_max[offset] = MAX(m_max_old, MAX(tmp_max, m_max_older)); + m_min_older = m_min_old; + m_max_older = m_max_old; + m_min_old = tmp_min; + m_max_old = tmp_max; + return (m_read_cache_mid[offset] = mid); + } + void reset() + { + m_head = m_tail; + } + void clear_data() + { + m_head = m_tail = 0; + memset(m_wave_buf, 0, sizeof(m_wave_buf)); + } + short get_cnt() + { + return (m_tail >= m_head) ? (m_tail - m_head) : (m_tail - m_head + WAVE_BUFFER_LEN); + } +private: + int read_data() + { + if (m_head == m_tail) + {//empty + //log_out("wave buf empty\n"); + return BUFFER_EMPTY; + } + int ret = m_wave_buf[m_head]; + m_head = (m_head + 1) % WAVE_BUFFER_LEN; + return ret; + } + short m_wave_buf[WAVE_BUFFER_LEN]; + short m_head; + short m_tail; + int m_min_old; + int m_max_old; + int m_min_older; + int m_max_older; + int m_last_data; + short m_read_cache_min[WAVE_READ_CACHE_LEN]; + short m_read_cache_mid[WAVE_READ_CACHE_LEN]; + short m_read_cache_max[WAVE_READ_CACHE_LEN]; + short m_read_cache_sum; + unsigned int m_refresh_sequence; +}; +#include +#include +#define CORRECT(x, high_limit, low_limit) {\ + x = (x > high_limit) ? high_limit : x;\ + x = (x < low_limit) ? low_limit : x;\ +}while(0) +#define WAVE_CURSOR_WIDTH 8 +#define WAVE_LINE_WIDTH 1 +#define WAVE_MARGIN 5 +typedef enum +{ + FILL_MODE, + SCAN_MODE +}E_WAVE_DRAW_MODE; +class c_wave_buffer; +class c_wave_ctrl : public c_wnd +{ +public: + c_wave_ctrl() + { + m_wave = 0; + m_bg_fb = 0; + m_wave_name_font = m_wave_unit_font = 0; + m_wave_name = m_wave_unit = 0; + m_max_data = 500; + m_min_data = 0; + m_wave_speed = 1; + m_wave_data_rate = 0; + m_wave_refresh_rate = 1000; + m_frame_len_map_index = 0; + m_wave_name_color = m_wave_unit_color = m_wave_color = GL_RGB(255, 0, 0); + m_back_color = GL_RGB(0, 0, 0); + } + virtual void on_init_children()//should be pre_create + { + c_rect rect; + get_screen_rect(rect); + m_wave_left = rect.m_left + WAVE_MARGIN; + m_wave_right = rect.m_right - WAVE_MARGIN; + m_wave_top = rect.m_top + WAVE_MARGIN; + m_wave_bottom = rect.m_bottom - WAVE_MARGIN; + m_wave_cursor = m_wave_left; + m_bg_fb = (unsigned int*)calloc(rect.width() * rect.height(), 4); + } + virtual void on_paint() + { + c_rect rect; + get_screen_rect(rect); + m_surface->fill_rect(rect, m_back_color, m_z_order); + //show name + c_word::draw_string(m_surface, m_z_order, m_wave_name, m_wave_left + 10, rect.m_top, m_wave_name_font, m_wave_name_color, GL_ARGB(0, 0, 0, 0)); + //show unit + c_word::draw_string(m_surface, m_z_order, m_wave_unit, m_wave_left + 60, rect.m_top, m_wave_unit_font, m_wave_unit_color, GL_ARGB(0, 0, 0, 0)); + save_background(); + } + void set_wave_name(char* wave_name){ m_wave_name = wave_name;} + void set_wave_unit(char* wave_unit){ m_wave_unit = wave_unit;} + void set_wave_name_font(const LATTICE_FONT_INFO* wave_name_font_type){ m_wave_name_font = wave_name_font_type;} + void set_wave_unit_font(const LATTICE_FONT_INFO* wave_unit_font_type){ m_wave_unit_font = wave_unit_font_type;} + void set_wave_name_color(unsigned int wave_name_color){ m_wave_name_color = wave_name_color;} + void set_wave_unit_color(unsigned int wave_unit_color){ m_wave_unit_color = wave_unit_color;} + void set_wave_color(unsigned int color){ m_wave_color = color;} + void set_wave_in_out_rate(unsigned int data_rate, unsigned int refresh_rate) + { + m_wave_data_rate = data_rate; + m_wave_refresh_rate = refresh_rate; + int read_times_per_second = m_wave_speed * 1000 / m_wave_refresh_rate; + memset(m_frame_len_map, 0, sizeof(m_frame_len_map)); + for (unsigned int i = 1; i < sizeof(m_frame_len_map) + 1; i++) + { + m_frame_len_map[i - 1] = data_rate * i / read_times_per_second - data_rate * (i - 1) / read_times_per_second; + } + m_frame_len_map_index = 0; + } + void set_wave_speed(unsigned int speed) + { + m_wave_speed = speed; + set_wave_in_out_rate(m_wave_data_rate, m_wave_refresh_rate); + } + void set_max_min(short max_data, short min_data) + { + m_max_data = max_data; + m_min_data = min_data; + } + void set_wave(c_wave_buffer* wave){m_wave = wave;} + c_wave_buffer* get_wave(){return m_wave;} + void clear_data() + { + if (m_wave == 0) + { + ASSERT(false); + return; + } + m_wave->clear_data(); + } + bool is_data_enough() + { + if (m_wave == 0) + { + ASSERT(false); + return false; + } + return (m_wave->get_cnt() - m_frame_len_map[m_frame_len_map_index] * m_wave_speed); + } + void refresh_wave(unsigned char frame) + { + if (m_wave == 0) + { + ASSERT(false); + return; + } + short max, min, mid; + for (short offset = 0; offset < m_wave_speed; offset++) + { + //get wave value + mid = m_wave->read_wave_data_by_frame(max, min, + m_frame_len_map[m_frame_len_map_index++], + frame, offset); + m_frame_len_map_index %= sizeof(m_frame_len_map); + //map to wave ctrl + int y_min, y_max; + if (m_max_data == m_min_data) + { + ASSERT(false); + } + y_max = m_wave_bottom + WAVE_LINE_WIDTH - (m_wave_bottom - m_wave_top) * (min - m_min_data) / (m_max_data - m_min_data); + y_min = m_wave_bottom - WAVE_LINE_WIDTH - (m_wave_bottom - m_wave_top) * (max - m_min_data) / (m_max_data - m_min_data); + mid = m_wave_bottom - (m_wave_bottom - m_wave_top) * (mid - m_min_data) / (m_max_data - m_min_data); + CORRECT(y_min, m_wave_bottom, m_wave_top); + CORRECT(y_max, m_wave_bottom, m_wave_top); + CORRECT(mid, m_wave_bottom, m_wave_top); + if (m_wave_cursor > m_wave_right) + { + m_wave_cursor = m_wave_left; + } + draw_smooth_vline(y_min, y_max, mid, m_wave_color); + restore_background(); + m_wave_cursor++; + } + } + void clear_wave() + { + m_surface->fill_rect(m_wave_left, m_wave_top, m_wave_right, m_wave_bottom, m_back_color, m_z_order); + m_wave_cursor = m_wave_left; + } +protected: + void draw_smooth_vline(int y_min, int y_max, int mid, unsigned int rgb) + { + int dy = y_max - y_min; + short r = GL_RGB_R(rgb); + short g = GL_RGB_G(rgb); + short b = GL_RGB_B(rgb); + int index = (dy >> 1) + 2; + int y; + m_surface->draw_pixel(m_wave_cursor, mid, rgb, m_z_order); + if (dy < 1) + { + return; + } + unsigned char cur_r, cur_g, cur_b; + unsigned int cur_rgb; + for (int i = 1; i <= (dy >> 1) + 1; ++i) + { + if ((mid + i) <= y_max) + { + y = mid + i; + cur_r = r * (index - i) / index; + cur_g = g * (index - i) / index; + cur_b = b * (index - i) / index; + cur_rgb = GL_RGB(cur_r, cur_g, cur_b); + m_surface->draw_pixel(m_wave_cursor, y, cur_rgb, m_z_order); + } + if ((mid - i) >= y_min) + { + y = mid - i; + cur_r = r * (index - i) / index; + cur_g = g * (index - i) / index; + cur_b = b * (index - i) / index; + cur_rgb = GL_RGB(cur_r, cur_g, cur_b); + m_surface->draw_pixel(m_wave_cursor, y, cur_rgb, m_z_order); + } + } + } + void restore_background() + { + int x = m_wave_cursor + WAVE_CURSOR_WIDTH; + if (x > m_wave_right) + { + x -= (m_wave_right - m_wave_left + 1); + } + c_rect rect; + get_screen_rect(rect); + register int width = rect.width(); + register int top = rect.m_top; + register int left = rect.m_left; + for (int y_pos = (m_wave_top - 1); y_pos <= (m_wave_bottom + 1); y_pos++) + { + (m_bg_fb) ? m_surface->draw_pixel(x, y_pos, m_bg_fb[(y_pos - top) * width + (x - left)], m_z_order) : m_surface->draw_pixel(x, y_pos, 0, m_z_order); + } + } + void save_background() + { + if (!m_bg_fb) + { + return; + } + c_rect rect; + get_screen_rect(rect); + register unsigned int* p_des = m_bg_fb; + for (int y = rect.m_top; y <= rect.m_bottom; y++) + { + for (int x = rect.m_left; x <= rect.m_right; x++) + { + *p_des++ = m_surface->get_pixel(x, y, m_z_order); + } + } + } + char* m_wave_name; + char* m_wave_unit; + const LATTICE_FONT_INFO* m_wave_name_font; + const LATTICE_FONT_INFO* m_wave_unit_font; + unsigned int m_wave_name_color; + unsigned int m_wave_unit_color; + unsigned int m_wave_color; + unsigned int m_back_color; + int m_wave_left; + int m_wave_right; + int m_wave_top; + int m_wave_bottom; + short m_max_data; + short m_min_data; + +private: + c_wave_buffer* m_wave; + unsigned int* m_bg_fb; //background frame buffer, could be used to draw scale line. + int m_wave_cursor; + int m_wave_speed; //pixels per refresh + unsigned int m_wave_data_rate; //data sample rate + unsigned int m_wave_refresh_rate;//refresh cycle in millisecond + unsigned char m_frame_len_map[64]; + unsigned char m_frame_len_map_index; +}; +#ifdef GUILITE_ON +c_bitmap_operator the_bitmap_op = c_bitmap_operator(); +c_image_operator* c_image::image_operator = &the_bitmap_op; +#endif + +#ifdef GUILITE_ON + +const void* c_theme::s_font_map[FONT_MAX]; +const void* c_theme::s_image_map[IMAGE_MAX]; +unsigned int c_theme::s_color_map[COLOR_MAX]; + +#endif + +#ifdef GUILITE_ON + +c_lattice_font_op the_lattice_font_op = c_lattice_font_op(); +c_font_operator* c_word::fontOperator = &the_lattice_font_op; + +#endif +#ifdef GUILITE_ON +#if (defined __linux__) || (defined __APPLE__) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define MAX_TIMER_CNT 10 +#define TIMER_UNIT 50//ms +static void(*do_assert)(const char* file, int line); +static void(*do_log_out)(const char* log); +void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)) +{ + do_assert = my_assert; + do_log_out = my_log_out; +} +void _assert(const char* file, int line) +{ + if(do_assert) + { + do_assert(file, line); + } + else + { + printf("assert@ file:%s, line:%d, error no: %d\n", file, line, errno); + } +} +void log_out(const char* log) +{ + if (do_log_out) + { + do_log_out(log); + } + else + { + printf("%s", log); + fflush(stdout); + } +} +typedef struct _timer_manage +{ + struct _timer_info + { + int state; /* on or off */ + int interval; + int elapse; /* 0~interval */ + void (* timer_proc) (void* param); + void* param; + }timer_info[MAX_TIMER_CNT]; + void (* old_sigfunc)(int); + void (* new_sigfunc)(int); +}_timer_manage_t; +static struct _timer_manage timer_manage; +static void* timer_routine(void*) +{ + int i; + while(true) + { + for(i = 0; i < MAX_TIMER_CNT; i++) + { + if(timer_manage.timer_info[i].state == 0) + { + continue; + } + timer_manage.timer_info[i].elapse++; + if(timer_manage.timer_info[i].elapse == timer_manage.timer_info[i].interval) + { + timer_manage.timer_info[i].elapse = 0; + timer_manage.timer_info[i].timer_proc(timer_manage.timer_info[i].param); + } + } + usleep(1000 * TIMER_UNIT); + } + return NULL; +} +static int init_mul_timer() +{ + static bool s_is_init = false; + if(s_is_init == true) + { + return 0; + } + memset(&timer_manage, 0, sizeof(struct _timer_manage)); + pthread_t pid; + pthread_create(&pid, NULL, timer_routine, NULL); + s_is_init = true; + return 1; +} +static int set_a_timer(int interval, void (* timer_proc)(void* param), void* param) +{ + init_mul_timer(); + int i; + if(timer_proc == NULL || interval <= 0) + { + return (-1); + } + for(i = 0; i < MAX_TIMER_CNT; i++) + { + if(timer_manage.timer_info[i].state == 1) + { + continue; + } + memset(&timer_manage.timer_info[i], 0, sizeof(timer_manage.timer_info[i])); + timer_manage.timer_info[i].timer_proc = timer_proc; + timer_manage.timer_info[i].param = param; + timer_manage.timer_info[i].interval = interval; + timer_manage.timer_info[i].elapse = 0; + timer_manage.timer_info[i].state = 1; + break; + } + if(i >= MAX_TIMER_CNT) + { + ASSERT(false); + return (-1); + } + return (i); +} +typedef void (*EXPIRE_ROUTINE)(void* arg); +EXPIRE_ROUTINE s_expire_function; +static c_fifo s_real_timer_fifo; +static void* real_timer_routine(void*) +{ + char dummy; + while(1) + { + if(s_real_timer_fifo.read(&dummy, 1) > 0) + { + if(s_expire_function)s_expire_function(0); + } + else + { + ASSERT(false); + } + } + return 0; +} +static void expire_real_timer(int sigo) +{ + char dummy = 0x33; + if(s_real_timer_fifo.write(&dummy, 1) <= 0) + { + ASSERT(false); + } +} +void start_real_timer(void (*func)(void* arg)) +{ + if(NULL == func) + { + return; + } + s_expire_function = func; + signal(SIGALRM, expire_real_timer); + struct itimerval value, ovalue; + value.it_value.tv_sec = 0; + value.it_value.tv_usec = REAL_TIME_TASK_CYCLE_MS * 1000; + value.it_interval.tv_sec = 0; + value.it_interval.tv_usec = REAL_TIME_TASK_CYCLE_MS * 1000; + setitimer(ITIMER_REAL, &value, &ovalue); + static pthread_t s_pid; + if(s_pid == 0) + { + pthread_create(&s_pid, NULL, real_timer_routine, NULL); + } +} +unsigned int get_cur_thread_id() +{ + return (unsigned long)pthread_self(); +} +void register_timer(int milli_second,void func(void* param), void* param) +{ + set_a_timer(milli_second/TIMER_UNIT,func, param); +} +long get_time_in_second() +{ + return time(NULL); /* + 8*60*60*/ +} +T_TIME get_time() +{ + T_TIME ret = {0}; + struct tm *fmt; + time_t timer; + timer = get_time_in_second(); + fmt = localtime(&timer); + ret.year = fmt->tm_year + 1900; + ret.month = fmt->tm_mon + 1; + ret.day = fmt->tm_mday; + ret.hour = fmt->tm_hour; + ret.minute = fmt->tm_min; + ret.second = fmt->tm_sec; + return ret; +} +T_TIME second_to_day(long second) +{ + T_TIME ret = {0}; + struct tm *fmt; + fmt = localtime(&second); + ret.year = fmt->tm_year + 1900; + ret.month = fmt->tm_mon + 1; + ret.day = fmt->tm_mday; + ret.hour = fmt->tm_hour; + ret.minute = fmt->tm_min; + ret.second = fmt->tm_sec; + return ret; +} +void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg) +{ + pthread_create((pthread_t*)thread_id, (pthread_attr_t const*)attr, start_routine, arg); +} +void thread_sleep(unsigned int milli_seconds) +{ + usleep(milli_seconds * 1000); +} +typedef struct { + unsigned short bfType; + unsigned int bfSize; + unsigned short bfReserved1; + unsigned short bfReserved2; + unsigned int bfOffBits; +}__attribute__((packed))FileHead; +typedef struct{ + unsigned int biSize; + int biWidth; + int biHeight; + unsigned short biPlanes; + unsigned short biBitCount; + unsigned int biCompress; + unsigned int biSizeImage; + int biXPelsPerMeter; + int biYPelsPerMeter; + unsigned int biClrUsed; + unsigned int biClrImportant; + unsigned int biRedMask; + unsigned int biGreenMask; + unsigned int biBlueMask; +}__attribute__((packed))Infohead; +int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data) +{ + FileHead bmp_head; + Infohead bmp_info; + int size = width * height * 2; + //initialize bmp head. + bmp_head.bfType = 0x4d42; + bmp_head.bfSize = size + sizeof(FileHead) + sizeof(Infohead); + bmp_head.bfReserved1 = bmp_head.bfReserved2 = 0; + bmp_head.bfOffBits = bmp_head.bfSize - size; + //initialize bmp info. + bmp_info.biSize = 40; + bmp_info.biWidth = width; + bmp_info.biHeight = height; + bmp_info.biPlanes = 1; + bmp_info.biBitCount = 16; + bmp_info.biCompress = 3; + bmp_info.biSizeImage = size; + bmp_info.biXPelsPerMeter = 0; + bmp_info.biYPelsPerMeter = 0; + bmp_info.biClrUsed = 0; + bmp_info.biClrImportant = 0; + //RGB565 + bmp_info.biRedMask = 0xF800; + bmp_info.biGreenMask = 0x07E0; + bmp_info.biBlueMask = 0x001F; + //copy the data + FILE *fp; + if(!(fp=fopen(filename,"wb"))) + { + return -1; + } + fwrite(&bmp_head, 1, sizeof(FileHead),fp); + fwrite(&bmp_info, 1, sizeof(Infohead),fp); + //fwrite(data, 1, size, fp);//top <-> bottom + for (int i = (height - 1); i >= 0; --i) + { + fwrite(&data[i * width * 2], 1, width * 2, fp); + } + + fclose(fp); + return 0; +} +c_fifo::c_fifo() +{ + m_head = m_tail = 0; + m_read_sem = malloc(sizeof(sem_t)); + m_write_mutex = malloc(sizeof(pthread_mutex_t)); + + sem_init((sem_t*)m_read_sem, 0, 0); + pthread_mutex_init((pthread_mutex_t*)m_write_mutex, 0); +} +int c_fifo::read(void* buf, int len) +{ + unsigned char* pbuf = (unsigned char*)buf; + int i = 0; + while(i < len) + { + if (m_tail == m_head) + {//empty + sem_wait((sem_t*)m_read_sem); + continue; + } + *pbuf++ = m_buf[m_head]; + m_head = (m_head + 1) % FIFO_BUFFER_LEN; + i++; + } + if(i != len) + { + ASSERT(false); + } + return i; +} +int c_fifo::write(void* buf, int len) +{ + unsigned char* pbuf = (unsigned char*)buf; + int i = 0; + int tail = m_tail; + pthread_mutex_lock((pthread_mutex_t*)m_write_mutex); + while(i < len) + { + if ((m_tail + 1) % FIFO_BUFFER_LEN == m_head) + {//full, clear data has been written; + m_tail = tail; + log_out("Warning: fifo full\n"); + pthread_mutex_unlock((pthread_mutex_t*)m_write_mutex); + return 0; + } + m_buf[m_tail] = *pbuf++; + m_tail = (m_tail + 1) % FIFO_BUFFER_LEN; + i++; + } + pthread_mutex_unlock((pthread_mutex_t*)m_write_mutex); + if(i != len) + { + ASSERT(false); + } + else + { + sem_post((sem_t*)m_read_sem); + } + return i; +} +#endif +#endif +#ifdef GUILITE_ON +#if (!defined _WIN32) && (!defined WIN32) && (!defined _WIN64) && (!defined WIN64) && (!defined __linux__) && (!defined __APPLE__) + +#include + +static void(*do_assert)(const char* file, int line); +static void(*do_log_out)(const char* log); +void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)) +{ + do_assert = my_assert; + do_log_out = my_log_out; +} + +void _assert(const char* file, int line) +{ + if(do_assert) + { + do_assert(file, line); + } + while(1); +} + +void log_out(const char* log) +{ + if (do_log_out) + { + do_log_out(log); + } +} + +long get_time_in_second() +{ + return 0; +} + +T_TIME second_to_day(long second) +{ + T_TIME ret = {0}; + return ret; +} + +T_TIME get_time() +{ + T_TIME ret = {0}; + return ret; +} + +void start_real_timer(void (*func)(void* arg)) +{ + log_out("Not support now"); +} + +void register_timer(int milli_second, void func(void* ptmr, void* parg)) +{ + log_out("Not support now"); +} + +unsigned int get_cur_thread_id() +{ + log_out("Not support now"); + return 0; +} + +void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg) +{ + log_out("Not support now"); +} + +extern "C" void delay_ms(unsigned short nms); +void thread_sleep(unsigned int milli_seconds) +{//MCU alway implemnet driver code in APP. + delay_ms(milli_seconds); +} + +int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data) +{ + log_out("Not support now"); + return 0; +} + +c_fifo::c_fifo() +{ + m_head = m_tail = 0; + m_read_sem = m_write_mutex = 0; +} + +int c_fifo::read(void* buf, int len) +{ + unsigned char* pbuf = (unsigned char*)buf; + int i = 0; + while(i < len) + { + if (m_tail == m_head) + {//empty + continue; + } + *pbuf++ = m_buf[m_head]; + m_head = (m_head + 1) % FIFO_BUFFER_LEN; + i++; + } + if(i != len) + { + ASSERT(false); + } + return i; +} + +int c_fifo::write(void* buf, int len) +{ + unsigned char* pbuf = (unsigned char*)buf; + int i = 0; + int tail = m_tail; + + while(i < len) + { + if ((m_tail + 1) % FIFO_BUFFER_LEN == m_head) + {//full, clear data has been written; + m_tail = tail; + log_out("Warning: fifo full\n"); + return 0; + } + m_buf[m_tail] = *pbuf++; + m_tail = (m_tail + 1) % FIFO_BUFFER_LEN; + i++; + } + + if(i != len) + { + ASSERT(false); + } + return i; +} + +#endif +#endif +#ifdef GUILITE_ON +#if (defined _WIN32) || (defined WIN32) || (defined _WIN64) || (defined WIN64) +#include +#include +#include +#include +#include +#include +#define MAX_TIMER_CNT 10 +#define TIMER_UNIT 50//ms +static void(*do_assert)(const char* file, int line); +static void(*do_log_out)(const char* log); +void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)) +{ + do_assert = my_assert; + do_log_out = my_log_out; +} +void _assert(const char* file, int line) +{ + static char s_buf[192]; + if (do_assert) + { + do_assert(file, line); + } + else + { + memset(s_buf, 0, sizeof(s_buf)); + sprintf_s(s_buf, sizeof(s_buf), "vvvvvvvvvvvvvvvvvvvvvvvvvvvv\n\nAssert@ file = %s, line = %d\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", file, line); + OutputDebugStringA(s_buf); + printf("%s", s_buf); + fflush(stdout); + assert(false); + } +} +void log_out(const char* log) +{ + if (do_log_out) + { + do_log_out(log); + } + else + { + printf("%s", log); + fflush(stdout); + OutputDebugStringA(log); + } +} +typedef struct _timer_manage +{ + struct _timer_info + { + int state; /* on or off */ + int interval; + int elapse; /* 0~interval */ + void (* timer_proc) (void* param); + void* param; + }timer_info[MAX_TIMER_CNT]; + void (* old_sigfunc)(int); + void (* new_sigfunc)(int); +}_timer_manage_t; +static struct _timer_manage timer_manage; +DWORD WINAPI timer_routine(LPVOID lpParam) +{ + int i; + while(true) + { + for(i = 0; i < MAX_TIMER_CNT; i++) + { + if(timer_manage.timer_info[i].state == 0) + { + continue; + } + timer_manage.timer_info[i].elapse++; + if(timer_manage.timer_info[i].elapse == timer_manage.timer_info[i].interval) + { + timer_manage.timer_info[i].elapse = 0; + timer_manage.timer_info[i].timer_proc(timer_manage.timer_info[i].param); + } + } + Sleep(TIMER_UNIT); + } + return 0; +} +static int init_mul_timer() +{ + static bool s_is_init = false; + if(s_is_init == true) + { + return 0; + } + memset(&timer_manage, 0, sizeof(struct _timer_manage)); + DWORD pid; + CreateThread(0, 0, timer_routine, 0, 0, &pid); + s_is_init = true; + return 1; +} +static int set_a_timer(int interval, void (* timer_proc) (void* param), void* param) +{ + init_mul_timer(); + int i; + if(timer_proc == 0 || interval <= 0) + { + return (-1); + } + for(i = 0; i < MAX_TIMER_CNT; i++) + { + if(timer_manage.timer_info[i].state == 1) + { + continue; + } + memset(&timer_manage.timer_info[i], 0, sizeof(timer_manage.timer_info[i])); + timer_manage.timer_info[i].timer_proc = timer_proc; + timer_manage.timer_info[i].param = param; + timer_manage.timer_info[i].interval = interval; + timer_manage.timer_info[i].elapse = 0; + timer_manage.timer_info[i].state = 1; + break; + } + if(i >= MAX_TIMER_CNT) + { + ASSERT(false); + return (-1); + } + return (i); +} +typedef void (*EXPIRE_ROUTINE)(void* arg); +EXPIRE_ROUTINE s_expire_function; +static c_fifo s_real_timer_fifo; +static DWORD WINAPI fire_real_timer(LPVOID lpParam) +{ + char dummy; + while(1) + { + if(s_real_timer_fifo.read(&dummy, 1) > 0) + { + if(s_expire_function)s_expire_function(0); + } + else + { + ASSERT(false); + } + } + return 0; +} +/*Win32 desktop only +static void CALLBACK trigger_real_timer(UINT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR) +{ + char dummy = 0x33; + s_real_timer_fifo.write(&dummy, 1); +} +*/ +static DWORD WINAPI trigger_real_timer(LPVOID lpParam) +{ + char dummy = 0x33; + while (1) + { + s_real_timer_fifo.write(&dummy, 1); + Sleep(REAL_TIME_TASK_CYCLE_MS); + } + return 0; +} +void start_real_timer(void (*func)(void* arg)) +{ + if(0 == func) + { + return; + } + s_expire_function = func; + //timeSetEvent(REAL_TIME_TASK_CYCLE_MS, 0, trigger_real_timer, 0, TIME_PERIODIC);//Win32 desktop only + static DWORD s_pid; + if(s_pid == 0) + { + CreateThread(0, 0, trigger_real_timer, 0, 0, &s_pid); + CreateThread(0, 0, fire_real_timer, 0, 0, &s_pid); + } +} +unsigned int get_cur_thread_id() +{ + return GetCurrentThreadId(); +} +void register_timer(int milli_second,void func(void* param), void* param) +{ + set_a_timer(milli_second/TIMER_UNIT,func, param); +} +long get_time_in_second() +{ + return (long)time(0); +} +T_TIME get_time() +{ + T_TIME ret = {0}; + + SYSTEMTIME time; + GetLocalTime(&time); + ret.year = time.wYear; + ret.month = time.wMonth; + ret.day = time.wDay; + ret.hour = time.wHour; + ret.minute = time.wMinute; + ret.second = time.wSecond; + return ret; +} +T_TIME second_to_day(long second) +{ + T_TIME ret; + ret.year = 1999; + ret.month = 10; + ret.date = 1; + ret.second = second % 60; + second /= 60; + ret.minute = second % 60; + second /= 60; + ret.hour = (second + 8) % 24;//China time zone. + return ret; +} +void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg) +{ + DWORD pid = 0; + CreateThread(0, 0, LPTHREAD_START_ROUTINE(start_routine), arg, 0, &pid); + *thread_id = pid; +} +void thread_sleep(unsigned int milli_seconds) +{ + Sleep(milli_seconds); +} +#pragma pack(push,1) +typedef struct { + unsigned short bfType; + unsigned int bfSize; + unsigned short bfReserved1; + unsigned short bfReserved2; + unsigned int bfOffBits; +}FileHead; +typedef struct { + unsigned int biSize; + int biWidth; + int biHeight; + unsigned short biPlanes; + unsigned short biBitCount; + unsigned int biCompress; + unsigned int biSizeImage; + int biXPelsPerMeter; + int biYPelsPerMeter; + unsigned int biClrUsed; + unsigned int biClrImportant; + unsigned int biRedMask; + unsigned int biGreenMask; + unsigned int biBlueMask; +}Infohead; +#pragma pack(pop) +int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data) +{ + FileHead bmp_head; + Infohead bmp_info; + int size = width * height * 2; + //initialize bmp head. + bmp_head.bfType = 0x4d42; + bmp_head.bfSize = size + sizeof(FileHead) + sizeof(Infohead); + bmp_head.bfReserved1 = bmp_head.bfReserved2 = 0; + bmp_head.bfOffBits = bmp_head.bfSize - size; + //initialize bmp info. + bmp_info.biSize = 40; + bmp_info.biWidth = width; + bmp_info.biHeight = height; + bmp_info.biPlanes = 1; + bmp_info.biBitCount = 16; + bmp_info.biCompress = 3; + bmp_info.biSizeImage = size; + bmp_info.biXPelsPerMeter = 0; + bmp_info.biYPelsPerMeter = 0; + bmp_info.biClrUsed = 0; + bmp_info.biClrImportant = 0; + //RGB565 + bmp_info.biRedMask = 0xF800; + bmp_info.biGreenMask = 0x07E0; + bmp_info.biBlueMask = 0x001F; + //copy the data + FILE *fp; + if (!(fp = fopen(filename, "wb"))) + { + return -1; + } + fwrite(&bmp_head, 1, sizeof(FileHead), fp); + fwrite(&bmp_info, 1, sizeof(Infohead), fp); + //fwrite(data, 1, size, fp);//top <-> bottom + for (int i = (height - 1); i >= 0; --i) + { + fwrite(&data[i * width * 2], 1, width * 2, fp); + } + fclose(fp); + return 0; +} +c_fifo::c_fifo() +{ + m_head = m_tail = 0; + m_read_sem = CreateSemaphore(0, // default security attributes + 0, // initial count + 1, // maximum count + 0); // unnamed semaphore + m_write_mutex = CreateMutex(0, false, 0); +} +int c_fifo::read(void* buf, int len) +{ + unsigned char* pbuf = (unsigned char*)buf; + int i = 0; + while (i < len) + { + if (m_tail == m_head) + {//empty + WaitForSingleObject(m_read_sem, INFINITE); + continue; + } + *pbuf++ = m_buf[m_head]; + m_head = (m_head + 1) % FIFO_BUFFER_LEN; + i++; + } + if (i != len) + { + ASSERT(false); + } + return i; +} +int c_fifo::write(void* buf, int len) +{ + unsigned char* pbuf = (unsigned char*)buf; + int i = 0; + int tail = m_tail; + WaitForSingleObject(m_write_mutex, INFINITE); + while (i < len) + { + if ((m_tail + 1) % FIFO_BUFFER_LEN == m_head) + {//full, clear data has been written; + m_tail = tail; + log_out("Warning: fifo full\n"); + ReleaseMutex(m_write_mutex); + return 0; + } + m_buf[m_tail] = *pbuf++; + m_tail = (m_tail + 1) % FIFO_BUFFER_LEN; + i++; + } + ReleaseMutex(m_write_mutex); + if (i != len) + { + ASSERT(false); + } + else + { + ReleaseSemaphore(m_read_sem, 1, 0); + } + return i; +} +#endif +#endif +#ifdef GUILITE_ON +DIALOG_ARRAY c_dialog::ms_the_dialogs[SURFACE_CNT_MAX]; +#endif +#ifdef GUILITE_ON +c_keyboard c_edit::s_keyboard; +#endif +#ifdef GUILITE_ON +static c_keyboard_button s_key_0, s_key_1, s_key_2, s_key_3, s_key_4, s_key_5, s_key_6, s_key_7, s_key_8, s_key_9; +static c_keyboard_button s_key_A, s_key_B, s_key_C, s_key_D, s_key_E, s_key_F, s_key_G, s_key_H, s_key_I, s_key_J; +static c_keyboard_button s_key_K, s_key_L, s_key_M, s_key_N, s_key_O, s_key_P, s_key_Q, s_key_R, s_key_S, s_key_T; +static c_keyboard_button s_key_U, s_key_V, s_key_W, s_key_X, s_key_Y, s_key_Z; +static c_keyboard_button s_key_dot, s_key_caps, s_key_space, s_key_enter, s_key_del, s_key_esc, s_key_num_switch; +WND_TREE g_key_board_children[] = +{ + //Row 1 + {&s_key_Q, 'Q', 0, POS_X(0), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_W, 'W', 0, POS_X(1), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_E, 'E', 0, POS_X(2), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_R, 'R', 0, POS_X(3), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_T, 'T', 0, POS_X(4), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_Y, 'Y', 0, POS_X(5), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_U, 'U', 0, POS_X(6), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_I, 'I', 0, POS_X(7), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_O, 'O', 0, POS_X(8), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_P, 'P', 0, POS_X(9), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, + //Row 2 + {&s_key_A, 'A', 0, ((KEY_WIDTH / 2) + POS_X(0)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_S, 'S', 0, ((KEY_WIDTH / 2) + POS_X(1)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_D, 'D', 0, ((KEY_WIDTH / 2) + POS_X(2)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_F, 'F', 0, ((KEY_WIDTH / 2) + POS_X(3)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_G, 'G', 0, ((KEY_WIDTH / 2) + POS_X(4)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_H, 'H', 0, ((KEY_WIDTH / 2) + POS_X(5)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_J, 'J', 0, ((KEY_WIDTH / 2) + POS_X(6)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_K, 'K', 0, ((KEY_WIDTH / 2) + POS_X(7)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_L, 'L', 0, ((KEY_WIDTH / 2) + POS_X(8)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, + //Row 3 + {&s_key_caps, 0x14, 0, POS_X(0), POS_Y(2), CAPS_WIDTH, KEY_HEIGHT}, + {&s_key_Z, 'Z', 0, ((KEY_WIDTH / 2) + POS_X(1)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_X, 'X', 0, ((KEY_WIDTH / 2) + POS_X(2)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_C, 'C', 0, ((KEY_WIDTH / 2) + POS_X(3)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_V, 'V', 0, ((KEY_WIDTH / 2) + POS_X(4)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_B, 'B', 0, ((KEY_WIDTH / 2) + POS_X(5)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_N, 'N', 0, ((KEY_WIDTH / 2) + POS_X(6)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_M, 'M', 0, ((KEY_WIDTH / 2) + POS_X(7)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_del, 0x7F, 0, ((KEY_WIDTH / 2) + POS_X(8)), POS_Y(2), DEL_WIDTH, KEY_HEIGHT}, + //Row 4 + {&s_key_esc, 0x1B, 0, POS_X(0), POS_Y(3), ESC_WIDTH, KEY_HEIGHT}, + {&s_key_num_switch, 0x90, 0, POS_X(2), POS_Y(3), SWITCH_WIDTH, KEY_HEIGHT}, + {&s_key_space, ' ', 0, ((KEY_WIDTH / 2) + POS_X(3)), POS_Y(3), SPACE_WIDTH, KEY_HEIGHT}, + {&s_key_dot, '.', 0, ((KEY_WIDTH / 2) + POS_X(6)), POS_Y(3), DOT_WIDTH, KEY_HEIGHT}, + {&s_key_enter, '\n', 0, POS_X(8), POS_Y(3), ENTER_WIDTH, KEY_HEIGHT}, + {0,0,0,0,0,0,0} +}; +WND_TREE g_number_board_children[] = +{ + {&s_key_1, '1', 0, POS_X(0), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_2, '2', 0, POS_X(1), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_3, '3', 0, POS_X(2), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_4, '4', 0, POS_X(0), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_5, '5', 0, POS_X(1), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_6, '6', 0, POS_X(2), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_7, '7', 0, POS_X(0), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_8, '8', 0, POS_X(1), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_9, '9', 0, POS_X(2), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, + + {&s_key_esc, 0x1B, 0, POS_X(0), POS_Y(3), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_0, '0', 0, POS_X(1), POS_Y(3), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_dot, '.', 0, POS_X(2), POS_Y(3), KEY_WIDTH, KEY_HEIGHT}, + {&s_key_del, 0x7F, 0, POS_X(3), POS_Y(0), KEY_WIDTH, KEY_HEIGHT * 2 + 2}, + {&s_key_enter,'\n', 0, POS_X(3), POS_Y(2), KEY_WIDTH, KEY_HEIGHT * 2 + 2}, + {0,0,0,0,0,0,0} +}; +#endif \ No newline at end of file diff --git a/src/teensy41/tft_t4.cpp b/src/teensy41/tft_t4.cpp new file mode 100644 index 00000000..1591eeff --- /dev/null +++ b/src/teensy41/tft_t4.cpp @@ -0,0 +1,86 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include "usb64_conf.h" +#include "controller_icon.h" +#include "usb64_logo.h" +#include "printf.h" +#include "GuiLite.h" + +#if (ENABLE_TFT_DISPLAY >= 1) +#include "ILI9341_t3n.h" +static ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO); +static DMAMEM uint16_t _framebuffer[320 * 240]; +#else +//Stub a framebuffer +static uint16_t _framebuffer[1]; +#endif + +struct EXTERNAL_GFX_OP t4_gfx_op; + +static void _draw_pixel(int x, int y, unsigned int rgb) +{ +#if (ENABLE_TFT_DISPLAY >= 1) + tft.drawPixel(x, y, GL_RGB_32_to_16(rgb)); +#endif +} + +static void _fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) +{ +#if (ENABLE_TFT_DISPLAY >= 1) + tft.fillRect(x0, y0, x1 - x0, y1 - y0, GL_RGB_32_to_16(rgb)); +#endif +} + +void tft_dev_draw(bool force) +{ +#if (ENABLE_TFT_DISPLAY >= 1) + if (!force && tft.asyncUpdateActive()) + { + return; + } + while (tft.asyncUpdateActive()) + ; + tft.updateScreenAsync(); +#endif +} + +static void _tft_assert(const char *file, int line) +{ + debug_print_error("[TFT] Error: Assert in %s on line %d\n", file, line); + while (1) + yield(); +} + +static void _tft_log_out(const char *log) +{ + debug_print_status(log); +} + +void tft_dev_init() +{ + t4_gfx_op.draw_pixel = _draw_pixel; + t4_gfx_op.fill_rect = _fill_rect; + +#if (ENABLE_TFT_DISPLAY >= 1) + tft.begin(); + tft.setRotation(TFT_ROTATION); + tft.setFrameBuffer(_framebuffer); + tft.useFrameBuffer(true); +#endif + + register_debug_function(_tft_assert, _tft_log_out); +} + +void *tft_dev_get_fb() +{ + return _framebuffer; +} + +bool tft_dev_is_busy() +{ +#if (ENABLE_TFT_DISPLAY >= 1) + return tft.asyncUpdateActive(); +#endif +} diff --git a/src/tft/Arial_14.cpp b/src/tft/Arial_14.cpp new file mode 100644 index 00000000..85e41bea --- /dev/null +++ b/src/tft/Arial_14.cpp @@ -0,0 +1,268 @@ +#include "GuiLite.h" + +static const unsigned char _32[] = { +0, 42, }; +static const unsigned char _33[] = { +0, 6, 36, 1, 197, 1, 36, 1, 197, 1, 36, 1, 153, 1, 36, 1, 153, 1, 0, 1, 153, 1, 0, 1, 111, 1, 0, 2, 36, 1, 197, 1, 0, 6, }; +static const unsigned char _35[] = { +0, 20, 153, 1, 73, 2, 153, 1, 0, 2, 197, 1, 36, 1, 111, 1, 73, 1, 153, 1, 255, 5, 0, 1, 36, 1, 197, 1, 0, 1, 255, 1, 0, 2, 111, 2, 36, 1, 197, 1, 0, 1, 153, 1, 255, 5, 0, 1, 197, 1, 36, 1, 153, 1, 73, 1, 0, 2, 197, 1, 0, 1, 197, 1, 36, 1, 0, 19, }; +static const unsigned char _37[] = { +0, 31, 111, 1, 255, 2, 0, 2, 36, 1, 255, 1, 0, 3, 255, 1, 0, 1, 111, 2, 0, 1, 153, 1, 73, 1, 0, 3, 255, 1, 0, 1, 111, 2, 73, 1, 197, 1, 0, 4, 111, 1, 255, 2, 0, 1, 197, 1, 36, 1, 0, 7, 73, 1, 153, 1, 73, 1, 255, 2, 36, 1, 0, 4, 197, 1, 36, 1, 197, 1, 36, 1, 73, 1, 153, 1, 0, 3, 111, 2, 0, 1, 197, 1, 36, 1, 73, 1, 153, 1, 0, 3, 255, 1, 0, 2, 73, 1, 255, 2, 36, 1, 0, 30, }; +static const unsigned char _39[] = { +0, 6, 36, 1, 197, 1, 36, 1, 197, 1, 0, 1, 153, 1, 0, 16, }; +static const unsigned char _40[] = { +0, 14, 36, 1, 197, 1, 0, 2, 197, 1, 0, 2, 73, 1, 111, 1, 0, 2, 153, 1, 73, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 153, 1, 73, 1, 0, 2, 73, 1, 111, 1, 0, 3, 197, 1, 0, 3, 36, 1, 197, 1, 0, 4, }; +static const unsigned char _41[] = { +0, 13, 153, 1, 36, 1, 0, 3, 197, 1, 0, 3, 111, 1, 73, 1, 0, 2, 36, 1, 153, 1, 0, 2, 36, 1, 197, 1, 0, 2, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 2, 111, 1, 73, 1, 0, 2, 197, 1, 0, 2, 153, 1, 36, 1, 0, 5, }; +static const unsigned char _43[] = { +0, 33, 197, 1, 0, 5, 197, 1, 0, 3, 255, 5, 0, 3, 197, 1, 0, 5, 197, 1, 0, 26, }; +static const unsigned char _44[] = { +0, 31, 153, 1, 73, 1, 0, 1, 73, 2, 0, 1, 111, 1, 0, 4, }; +static const unsigned char _45[] = { +0, 32, 73, 1, 255, 3, 0, 20, }; +static const unsigned char _46[] = { +0, 31, 153, 1, 73, 1, 0, 9, }; +static const unsigned char _47[] = { +0, 11, 111, 1, 0, 2, 197, 1, 0, 1, 36, 1, 197, 1, 0, 1, 73, 1, 111, 1, 0, 1, 153, 1, 73, 1, 0, 1, 255, 1, 0, 1, 73, 1, 153, 1, 0, 1, 111, 2, 0, 10, }; +static const unsigned char _48[] = { +0, 20, 255, 2, 153, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 153, 1, 111, 1, 0, 1, 197, 1, 73, 1, 0, 2, 255, 2, 153, 1, 0, 19, }; +static const unsigned char _49[] = { +0, 21, 153, 1, 73, 1, 0, 3, 153, 1, 255, 1, 73, 1, 0, 2, 111, 1, 73, 1, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 19, }; +static const unsigned char _50[] = { +0, 19, 111, 1, 255, 3, 0, 1, 36, 1, 255, 1, 0, 2, 111, 1, 153, 1, 0, 4, 36, 1, 197, 1, 0, 4, 153, 1, 73, 1, 0, 3, 153, 1, 111, 1, 0, 3, 197, 1, 111, 1, 0, 3, 197, 1, 73, 1, 0, 3, 73, 1, 255, 4, 197, 1, 0, 18, }; +static const unsigned char _51[] = { +0, 19, 73, 1, 255, 2, 153, 1, 0, 2, 255, 1, 0, 2, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 2, 36, 1, 255, 1, 153, 1, 0, 5, 73, 1, 153, 1, 0, 4, 36, 1, 197, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 73, 1, 255, 2, 197, 1, 0, 19, }; +static const unsigned char _52[] = { +0, 21, 36, 1, 197, 1, 0, 4, 197, 2, 0, 3, 111, 1, 153, 1, 197, 1, 0, 2, 36, 1, 197, 1, 36, 1, 197, 1, 0, 2, 197, 1, 36, 2, 197, 1, 0, 1, 36, 1, 255, 4, 197, 1, 0, 3, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 19, }; +static const unsigned char _53[] = { +0, 19, 73, 1, 255, 3, 73, 1, 0, 1, 111, 2, 0, 4, 197, 1, 73, 1, 0, 4, 255, 1, 197, 1, 255, 2, 0, 3, 36, 1, 0, 1, 36, 1, 153, 1, 0, 4, 36, 1, 197, 1, 0, 1, 255, 1, 0, 2, 36, 1, 153, 1, 0, 1, 73, 1, 255, 2, 197, 1, 0, 19, }; +static const unsigned char _54[] = { +0, 19, 36, 1, 255, 3, 0, 2, 197, 1, 36, 1, 0, 1, 111, 1, 153, 1, 36, 1, 197, 1, 0, 4, 73, 1, 153, 1, 197, 1, 255, 2, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 153, 1, 73, 1, 153, 1, 0, 2, 36, 1, 197, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 36, 1, 255, 2, 197, 1, 0, 19, }; +static const unsigned char _55[] = { +0, 18, 36, 1, 255, 4, 197, 1, 0, 4, 197, 1, 73, 1, 0, 3, 73, 1, 153, 1, 0, 4, 197, 1, 36, 1, 0, 3, 73, 1, 197, 1, 0, 4, 153, 1, 73, 1, 0, 4, 197, 1, 36, 1, 0, 4, 255, 1, 0, 21, }; +static const unsigned char _56[] = { +0, 19, 36, 1, 255, 3, 0, 2, 197, 1, 36, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 2, 197, 1, 255, 1, 111, 1, 0, 2, 255, 1, 36, 1, 0, 1, 111, 1, 153, 1, 36, 1, 197, 1, 0, 3, 255, 1, 0, 1, 255, 1, 36, 1, 0, 1, 73, 1, 197, 1, 0, 1, 73, 1, 255, 3, 0, 19, }; +static const unsigned char _57[] = { +0, 19, 73, 1, 255, 2, 153, 1, 0, 2, 255, 1, 36, 1, 0, 1, 111, 2, 36, 1, 197, 1, 0, 2, 36, 1, 197, 1, 0, 1, 255, 1, 36, 1, 0, 1, 111, 1, 197, 1, 0, 1, 73, 1, 255, 2, 153, 1, 197, 1, 0, 4, 73, 1, 153, 1, 0, 1, 255, 1, 0, 2, 197, 1, 73, 1, 0, 1, 73, 1, 255, 2, 153, 1, 0, 19, }; +static const unsigned char _58[] = { +0, 16, 153, 1, 73, 1, 0, 13, 153, 1, 73, 1, 0, 9, }; +static const unsigned char _59[] = { +0, 16, 153, 1, 73, 1, 0, 13, 153, 1, 73, 1, 0, 1, 73, 2, 0, 1, 111, 1, 0, 4, }; +static const unsigned char _60[] = { +0, 34, 111, 1, 153, 1, 0, 2, 197, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 5, 197, 1, 255, 1, 111, 1, 0, 5, 111, 1, 153, 1, 0, 24, }; +static const unsigned char _61[] = { +0, 37, 255, 4, 153, 1, 0, 7, 255, 4, 153, 1, 0, 30, }; +static const unsigned char _62[] = { +0, 31, 255, 1, 36, 1, 0, 5, 197, 1, 255, 1, 153, 1, 0, 5, 73, 1, 197, 1, 0, 2, 197, 1, 255, 1, 153, 1, 0, 2, 255, 1, 36, 1, 0, 27, }; +static const unsigned char _63[] = { +0, 19, 73, 1, 255, 3, 0, 2, 255, 1, 0, 2, 73, 1, 197, 1, 0, 4, 73, 1, 197, 1, 0, 3, 73, 1, 255, 1, 0, 3, 36, 1, 255, 1, 0, 4, 73, 1, 153, 1, 0, 10, 73, 1, 153, 1, 0, 20, }; +static const unsigned char _64[] = { +0, 36, 36, 1, 255, 4, 111, 1, 0, 4, 153, 1, 255, 1, 0, 4, 197, 1, 153, 1, 0, 2, 73, 1, 197, 1, 0, 1, 153, 1, 255, 1, 197, 1, 153, 1, 73, 1, 197, 1, 73, 1, 0, 1, 197, 1, 73, 1, 111, 1, 153, 1, 0, 1, 73, 1, 255, 1, 0, 1, 73, 1, 153, 1, 0, 1, 255, 1, 0, 1, 255, 1, 36, 1, 0, 1, 36, 1, 197, 1, 0, 1, 73, 1, 153, 1, 0, 1, 255, 1, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 1, 153, 1, 111, 1, 0, 1, 255, 1, 36, 1, 255, 1, 36, 1, 0, 1, 255, 1, 111, 1, 73, 1, 255, 1, 0, 2, 153, 2, 73, 1, 255, 2, 111, 1, 255, 2, 0, 4, 197, 2, 0, 5, 197, 2, 0, 3, 111, 1, 255, 5, 36, 1, 0, 12, }; +static const unsigned char _65[] = { +0, 27, 73, 1, 197, 1, 0, 6, 197, 1, 111, 1, 73, 1, 0, 4, 73, 1, 153, 1, 36, 1, 153, 1, 0, 4, 153, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 2, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 2, 153, 1, 255, 5, 36, 1, 0, 1, 255, 1, 0, 4, 111, 3, 73, 1, 0, 5, 255, 1, 0, 24, }; +static const unsigned char _66[] = { +0, 22, 197, 1, 255, 3, 153, 1, 0, 2, 197, 1, 36, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 153, 1, 36, 1, 0, 1, 197, 1, 255, 4, 0, 2, 197, 1, 36, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 2, 153, 1, 73, 1, 0, 1, 197, 1, 255, 3, 153, 1, 0, 22, }; +static const unsigned char _67[] = { +0, 23, 111, 1, 255, 2, 153, 1, 0, 2, 111, 1, 197, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 36, 2, 0, 1, 255, 1, 0, 6, 255, 1, 0, 6, 197, 1, 36, 1, 0, 5, 111, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 255, 2, 197, 1, 0, 22, }; +static const unsigned char _68[] = { +0, 22, 255, 4, 111, 1, 0, 2, 255, 1, 0, 3, 197, 1, 73, 1, 0, 1, 255, 1, 0, 3, 73, 1, 153, 1, 0, 1, 255, 1, 0, 3, 36, 1, 197, 1, 0, 1, 255, 1, 0, 3, 36, 1, 197, 1, 0, 1, 255, 1, 0, 3, 73, 1, 153, 1, 0, 1, 255, 1, 0, 3, 197, 1, 73, 1, 0, 1, 255, 4, 111, 1, 0, 22, }; +static const unsigned char _69[] = { +0, 19, 255, 4, 111, 1, 0, 1, 255, 1, 0, 5, 255, 1, 0, 5, 255, 4, 36, 1, 0, 1, 255, 1, 0, 5, 255, 1, 0, 5, 255, 1, 0, 5, 255, 4, 153, 1, 0, 18, }; +static const unsigned char _70[] = { +0, 19, 197, 1, 255, 3, 197, 1, 0, 1, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 255, 3, 36, 1, 0, 1, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 21, }; +static const unsigned char _71[] = { +0, 26, 111, 1, 255, 3, 111, 1, 0, 2, 111, 1, 197, 1, 0, 3, 255, 1, 73, 1, 0, 1, 255, 1, 36, 1, 0, 3, 73, 1, 111, 1, 36, 1, 197, 1, 0, 6, 36, 1, 197, 1, 0, 2, 73, 1, 255, 2, 153, 1, 0, 1, 255, 1, 36, 1, 0, 3, 73, 1, 153, 1, 0, 1, 111, 1, 197, 1, 0, 3, 153, 2, 0, 2, 73, 1, 255, 3, 153, 1, 0, 25, }; +static const unsigned char _72[] = { +0, 22, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 255, 4, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 21, }; +static const unsigned char _73[] = { +0, 7, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 6, }; +static const unsigned char _74[] = { +0, 18, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 255, 2, 153, 1, 0, 16, }; +static const unsigned char _75[] = { +0, 22, 197, 1, 36, 1, 0, 2, 153, 1, 255, 1, 0, 1, 197, 1, 36, 1, 0, 1, 153, 2, 0, 2, 197, 1, 36, 1, 153, 2, 0, 3, 197, 2, 255, 1, 36, 1, 0, 3, 197, 1, 111, 2, 197, 1, 0, 3, 197, 1, 36, 1, 0, 1, 197, 1, 153, 1, 0, 2, 197, 1, 36, 1, 0, 2, 255, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 2, 73, 1, 255, 1, 0, 21, }; +static const unsigned char _76[] = { +0, 19, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 255, 4, 0, 18, }; +static const unsigned char _77[] = { +0, 25, 197, 1, 153, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 2, 0, 2, 111, 1, 197, 1, 73, 1, 0, 1, 197, 1, 111, 1, 36, 1, 0, 1, 153, 1, 111, 1, 73, 1, 0, 1, 197, 1, 73, 1, 111, 1, 0, 1, 197, 1, 111, 1, 73, 1, 0, 1, 197, 1, 36, 1, 153, 1, 36, 1, 111, 2, 73, 1, 0, 1, 197, 1, 36, 1, 153, 1, 111, 1, 73, 1, 111, 1, 73, 1, 0, 1, 197, 1, 36, 1, 111, 1, 197, 1, 0, 1, 111, 1, 73, 1, 0, 1, 197, 1, 36, 2, 197, 1, 0, 1, 111, 1, 73, 1, 0, 24, }; +static const unsigned char _78[] = { +0, 22, 197, 1, 111, 1, 0, 2, 111, 2, 0, 1, 197, 1, 255, 1, 0, 2, 111, 2, 0, 1, 197, 1, 111, 2, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 197, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 73, 1, 111, 3, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 111, 1, 0, 21, }; +static const unsigned char _79[] = { +0, 26, 111, 1, 255, 3, 0, 3, 111, 1, 197, 1, 0, 2, 73, 1, 255, 1, 0, 2, 197, 1, 36, 1, 0, 3, 153, 1, 73, 1, 0, 1, 255, 1, 0, 4, 111, 2, 0, 1, 255, 1, 0, 4, 111, 2, 0, 1, 197, 1, 36, 1, 0, 3, 153, 1, 73, 1, 0, 1, 111, 1, 197, 1, 0, 2, 73, 1, 255, 1, 0, 3, 111, 1, 255, 3, 0, 26, }; +static const unsigned char _80[] = { +0, 19, 197, 1, 255, 3, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 255, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 0, 1, 197, 1, 36, 1, 0, 2, 255, 1, 0, 1, 197, 1, 255, 3, 111, 1, 0, 1, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 21, }; +static const unsigned char _81[] = { +0, 26, 73, 1, 255, 3, 0, 3, 73, 1, 255, 1, 0, 2, 73, 1, 255, 1, 0, 2, 153, 1, 73, 1, 0, 3, 153, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 3, 111, 2, 0, 1, 197, 1, 36, 1, 0, 3, 111, 2, 0, 1, 153, 1, 73, 1, 0, 1, 73, 1, 0, 1, 153, 1, 73, 1, 0, 1, 73, 1, 255, 1, 0, 1, 73, 1, 255, 1, 197, 1, 0, 3, 73, 1, 255, 2, 153, 1, 197, 2, 0, 24, }; +static const unsigned char _82[] = { +0, 22, 197, 1, 255, 4, 0, 2, 197, 1, 36, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 255, 3, 197, 1, 0, 2, 197, 1, 36, 1, 0, 1, 153, 1, 111, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 2, 73, 1, 255, 1, 0, 21, }; +static const unsigned char _83[] = { +0, 23, 255, 3, 153, 1, 0, 2, 197, 1, 73, 1, 0, 2, 197, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 5, 73, 1, 255, 2, 73, 1, 0, 6, 153, 1, 255, 1, 73, 1, 0, 5, 36, 1, 197, 1, 0, 1, 255, 1, 73, 1, 0, 2, 111, 1, 153, 1, 0, 1, 36, 1, 255, 3, 197, 1, 0, 22, }; +static const unsigned char _84[] = { +0, 18, 197, 1, 255, 5, 0, 2, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 20, }; +static const unsigned char _85[] = { +0, 22, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 153, 1, 111, 1, 0, 1, 36, 1, 255, 1, 0, 3, 255, 3, 36, 1, 0, 22, }; +static const unsigned char _86[] = { +0, 24, 111, 1, 197, 1, 0, 4, 36, 1, 255, 1, 0, 1, 255, 1, 36, 1, 0, 3, 111, 1, 153, 1, 0, 1, 111, 2, 0, 3, 197, 1, 36, 1, 0, 1, 36, 1, 255, 1, 0, 2, 73, 1, 197, 1, 0, 3, 153, 1, 73, 1, 0, 1, 153, 1, 73, 1, 0, 3, 73, 1, 153, 1, 36, 1, 255, 1, 0, 5, 197, 1, 153, 1, 111, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 26, }; +static const unsigned char _87[] = { +0, 30, 73, 1, 153, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 197, 1, 36, 1, 197, 1, 0, 2, 153, 1, 111, 1, 73, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 0, 2, 153, 1, 36, 1, 153, 1, 0, 1, 73, 1, 111, 1, 0, 1, 153, 1, 73, 1, 36, 1, 153, 1, 0, 1, 197, 1, 0, 1, 153, 1, 73, 1, 0, 1, 73, 1, 111, 2, 73, 1, 0, 1, 153, 1, 36, 1, 197, 1, 0, 2, 36, 1, 153, 2, 36, 1, 0, 1, 111, 1, 73, 1, 197, 1, 0, 3, 153, 1, 197, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 3, 153, 2, 0, 3, 255, 1, 73, 1, 0, 31, }; +static const unsigned char _88[] = { +0, 21, 36, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 0, 1, 73, 1, 197, 1, 0, 2, 255, 1, 0, 3, 153, 1, 73, 1, 111, 1, 73, 1, 0, 4, 255, 1, 153, 1, 0, 4, 36, 1, 153, 1, 255, 1, 0, 4, 197, 1, 36, 1, 111, 1, 153, 1, 0, 2, 111, 2, 0, 2, 197, 1, 73, 1, 111, 1, 197, 1, 0, 3, 36, 1, 255, 1, 0, 21, }; +static const unsigned char _89[] = { +0, 24, 111, 1, 153, 1, 0, 4, 73, 1, 197, 1, 0, 1, 111, 2, 0, 3, 255, 1, 0, 3, 197, 1, 36, 1, 0, 1, 153, 1, 36, 1, 0, 3, 36, 1, 197, 1, 73, 1, 111, 1, 0, 5, 73, 1, 197, 1, 0, 6, 73, 1, 153, 1, 0, 6, 73, 1, 153, 1, 0, 6, 73, 1, 153, 1, 0, 27, }; +static const unsigned char _90[] = { +0, 22, 255, 6, 0, 5, 197, 1, 111, 1, 0, 4, 153, 2, 0, 4, 111, 1, 197, 1, 0, 4, 73, 1, 255, 1, 0, 4, 36, 1, 255, 1, 36, 1, 0, 4, 255, 1, 73, 1, 0, 4, 111, 1, 255, 6, 0, 21, }; +static const unsigned char _91[] = { +0, 10, 255, 2, 0, 1, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 2, 0, 3, }; +static const unsigned char _93[] = { +0, 9, 111, 1, 255, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 111, 1, 255, 1, 153, 1, 0, 3, }; +static const unsigned char _95[] = { +0, 72, 197, 1, 255, 5, 0, 6, }; +static const unsigned char _97[] = { +0, 31, 36, 1, 255, 3, 0, 2, 197, 1, 36, 1, 0, 1, 153, 1, 73, 1, 0, 2, 197, 1, 255, 2, 111, 1, 0, 1, 255, 1, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 255, 1, 0, 2, 255, 1, 111, 1, 0, 1, 153, 1, 255, 2, 153, 2, 0, 18, }; +static const unsigned char _98[] = { +0, 19, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 153, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 73, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 73, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 153, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 153, 1, 255, 2, 0, 19, }; +static const unsigned char _99[] = { +0, 32, 197, 1, 255, 2, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 36, 1, 255, 1, 0, 1, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 153, 1, 111, 1, 0, 2, 255, 1, 0, 2, 197, 1, 255, 2, 73, 1, 0, 18, }; +static const unsigned char _100[] = { +0, 22, 111, 1, 153, 1, 0, 4, 111, 1, 153, 1, 0, 1, 36, 1, 255, 2, 153, 2, 0, 1, 197, 1, 73, 1, 0, 1, 197, 1, 153, 1, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 73, 1, 0, 1, 153, 2, 0, 1, 36, 1, 255, 2, 197, 1, 153, 1, 0, 18, }; +static const unsigned char _101[] = { +0, 32, 255, 3, 0, 2, 197, 1, 36, 1, 0, 1, 73, 1, 153, 1, 0, 1, 255, 4, 197, 1, 0, 1, 255, 1, 0, 5, 197, 1, 111, 1, 0, 1, 111, 1, 153, 1, 0, 2, 255, 3, 0, 19, }; +static const unsigned char _102[] = { +0, 14, 111, 1, 255, 1, 0, 2, 197, 1, 36, 1, 0, 1, 153, 1, 255, 2, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 12, }; +static const unsigned char _103[] = { +0, 32, 255, 2, 111, 1, 153, 1, 0, 1, 153, 1, 111, 1, 0, 1, 153, 2, 0, 1, 197, 1, 36, 1, 0, 1, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 73, 1, 153, 1, 0, 1, 153, 1, 111, 1, 0, 1, 153, 2, 0, 2, 255, 2, 153, 2, 0, 4, 111, 2, 0, 1, 153, 1, 255, 2, 197, 1, 0, 7, }; +static const unsigned char _104[] = { +0, 19, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 111, 1, 0, 1, 153, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 18, }; +static const unsigned char _105[] = { +0, 7, 197, 1, 0, 3, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 6, }; +static const unsigned char _106[] = { +0, 7, 197, 1, 0, 3, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 255, 2, 0, 2, }; +static const unsigned char _107[] = { +0, 16, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 2, 255, 1, 0, 1, 197, 1, 36, 1, 197, 1, 0, 2, 197, 1, 255, 1, 73, 1, 0, 2, 197, 1, 73, 1, 197, 1, 0, 2, 197, 1, 36, 1, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 1, 255, 1, 0, 15, }; +static const unsigned char _108[] = { +0, 7, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 6, }; +static const unsigned char _109[] = { +0, 41, 197, 1, 153, 1, 255, 1, 197, 1, 111, 1, 255, 1, 197, 1, 0, 1, 197, 1, 111, 1, 0, 1, 197, 1, 111, 1, 0, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 0, 24, }; +static const unsigned char _110[] = { +0, 31, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 73, 1, 0, 1, 153, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 18, }; +static const unsigned char _111[] = { +0, 31, 36, 1, 255, 2, 197, 1, 0, 2, 197, 1, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 36, 1, 255, 2, 153, 1, 0, 19, }; +static const unsigned char _112[] = { +0, 31, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 111, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 111, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 9, }; +static const unsigned char _113[] = { +0, 31, 73, 1, 255, 2, 111, 1, 153, 1, 0, 1, 255, 1, 36, 1, 0, 1, 197, 1, 153, 1, 73, 1, 153, 1, 0, 2, 73, 1, 153, 1, 73, 1, 153, 1, 0, 2, 73, 1, 153, 1, 0, 1, 255, 1, 36, 1, 0, 1, 153, 2, 0, 1, 73, 1, 255, 2, 153, 2, 0, 4, 73, 1, 153, 1, 0, 4, 73, 1, 153, 1, 0, 6, }; +static const unsigned char _114[] = { +0, 21, 197, 1, 153, 1, 255, 1, 0, 1, 197, 1, 111, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 13, }; +static const unsigned char _115[] = { +0, 31, 111, 1, 255, 2, 197, 1, 0, 2, 255, 1, 0, 2, 153, 1, 73, 1, 0, 1, 197, 1, 255, 2, 0, 5, 197, 1, 255, 1, 153, 1, 36, 1, 255, 1, 0, 2, 73, 1, 197, 1, 0, 1, 73, 1, 255, 3, 36, 1, 0, 18, }; +static const unsigned char _116[] = { +0, 10, 153, 1, 36, 1, 0, 1, 197, 1, 36, 1, 111, 1, 255, 2, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 153, 1, 255, 1, 0, 9, }; +static const unsigned char _117[] = { +0, 31, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 153, 1, 111, 1, 0, 1, 197, 1, 73, 1, 0, 1, 197, 1, 111, 1, 0, 1, 73, 1, 255, 2, 153, 1, 111, 1, 0, 18, }; +static const unsigned char _118[] = { +0, 30, 36, 1, 197, 1, 0, 2, 36, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 73, 1, 111, 1, 0, 1, 197, 1, 0, 3, 255, 1, 73, 1, 153, 1, 0, 3, 153, 2, 73, 1, 0, 3, 73, 1, 255, 1, 0, 20, }; +static const unsigned char _119[] = { +0, 51, 197, 1, 36, 1, 0, 1, 73, 1, 255, 1, 0, 2, 111, 2, 0, 1, 111, 2, 0, 1, 153, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 73, 1, 111, 1, 36, 1, 197, 1, 0, 3, 197, 1, 73, 1, 153, 1, 0, 1, 197, 1, 111, 2, 0, 3, 111, 1, 197, 1, 73, 1, 0, 1, 197, 1, 153, 1, 36, 1, 0, 3, 36, 1, 255, 1, 36, 1, 0, 1, 111, 1, 197, 1, 0, 32, }; +static const unsigned char _120[] = { +0, 30, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 197, 1, 0, 1, 73, 1, 197, 1, 73, 1, 255, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 197, 1, 255, 1, 111, 1, 0, 2, 111, 1, 153, 1, 0, 1, 255, 1, 36, 1, 111, 1, 255, 1, 0, 2, 73, 1, 255, 1, 0, 18, }; +static const unsigned char _121[] = { +0, 30, 73, 1, 197, 1, 0, 3, 255, 1, 0, 1, 197, 1, 73, 1, 0, 1, 111, 1, 153, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 2, 255, 1, 36, 1, 197, 1, 0, 3, 153, 1, 197, 1, 73, 1, 0, 3, 36, 1, 255, 1, 0, 4, 111, 2, 0, 3, 255, 2, 0, 9, }; +static const unsigned char _122[] = { +0, 31, 153, 1, 255, 3, 197, 1, 0, 4, 153, 1, 36, 1, 0, 3, 153, 1, 73, 1, 0, 3, 111, 2, 0, 3, 73, 1, 153, 1, 0, 4, 255, 4, 197, 1, 0, 18, }; +static const unsigned char _14849714[] = { +0, 38, 36, 1, 0, 10, 197, 1, 73, 1, 0, 8, 73, 1, 255, 1, 197, 1, 0, 8, 197, 1, 255, 2, 73, 1, 0, 6, 73, 1, 255, 3, 197, 1, 0, 6, 197, 1, 255, 4, 73, 1, 0, 4, 73, 1, 255, 5, 197, 1, 0, 4, 197, 1, 255, 6, 111, 1, 0, 34, }; +static const unsigned char _14849724[] = { +0, 46, 197, 1, 255, 6, 111, 1, 0, 4, 255, 5, 153, 1, 0, 5, 111, 1, 255, 4, 36, 1, 0, 6, 255, 3, 153, 1, 0, 7, 111, 1, 255, 2, 36, 1, 0, 8, 255, 1, 153, 1, 0, 9, 111, 1, 36, 1, 0, 37, }; +static LATTICE lattice_array[] = { + {32, 3, _32}, + {33, 2, _33}, + {35, 6, _35}, + {37, 10, _37}, + {39, 2, _39}, + {40, 4, _40}, + {41, 4, _41}, + {43, 6, _43}, + {44, 3, _44}, + {45, 4, _45}, + {46, 3, _46}, + {47, 3, _47}, + {48, 6, _48}, + {49, 6, _49}, + {50, 6, _50}, + {51, 6, _51}, + {52, 6, _52}, + {53, 6, _53}, + {54, 6, _54}, + {55, 6, _55}, + {56, 6, _56}, + {57, 6, _57}, + {58, 3, _58}, + {59, 3, _59}, + {60, 6, _60}, + {61, 6, _61}, + {62, 6, _62}, + {63, 6, _63}, + {64, 11, _64}, + {65, 8, _65}, + {66, 7, _66}, + {67, 7, _67}, + {68, 7, _68}, + {69, 6, _69}, + {70, 6, _70}, + {71, 8, _71}, + {72, 7, _72}, + {73, 2, _73}, + {74, 5, _74}, + {75, 7, _75}, + {76, 6, _76}, + {77, 8, _77}, + {78, 7, _78}, + {79, 8, _79}, + {80, 6, _80}, + {81, 8, _81}, + {82, 7, _82}, + {83, 7, _83}, + {84, 6, _84}, + {85, 7, _85}, + {86, 8, _86}, + {87, 10, _87}, + {88, 7, _88}, + {89, 8, _89}, + {90, 7, _90}, + {91, 3, _91}, + {93, 3, _93}, + {95, 6, _95}, + {97, 6, _97}, + {98, 6, _98}, + {99, 6, _99}, + {100, 6, _100}, + {101, 6, _101}, + {102, 4, _102}, + {103, 6, _103}, + {104, 6, _104}, + {105, 2, _105}, + {106, 2, _106}, + {107, 5, _107}, + {108, 2, _108}, + {109, 8, _109}, + {110, 6, _110}, + {111, 6, _111}, + {112, 6, _112}, + {113, 6, _113}, + {114, 4, _114}, + {115, 6, _115}, + {116, 3, _116}, + {117, 6, _117}, + {118, 6, _118}, + {119, 10, _119}, + {120, 6, _120}, + {121, 6, _121}, + {122, 6, _122}, + {14849714, 11, _14849714}, + {14849724, 11, _14849724}, +}; +extern const LATTICE_FONT_INFO Arial_14_GL; +const LATTICE_FONT_INFO Arial_14_GL ={ + 14, + 86, + lattice_array +}; diff --git a/src/tft/Arial_19.cpp b/src/tft/Arial_19.cpp new file mode 100644 index 00000000..de5027e5 --- /dev/null +++ b/src/tft/Arial_19.cpp @@ -0,0 +1,268 @@ +#include "GuiLite.h" + +static const unsigned char _32[] = { +0, 95, }; +static const unsigned char _33[] = { +0, 17, 255, 1, 197, 1, 0, 3, 255, 1, 197, 1, 0, 3, 255, 1, 197, 1, 0, 3, 255, 1, 197, 1, 0, 3, 255, 1, 197, 1, 0, 3, 197, 1, 153, 1, 0, 3, 197, 1, 153, 1, 0, 3, 153, 1, 111, 1, 0, 3, 153, 1, 111, 1, 0, 3, 153, 1, 111, 1, 0, 8, 255, 1, 197, 1, 0, 21, }; +static const unsigned char _35[] = { +0, 30, 111, 2, 0, 2, 153, 1, 73, 1, 0, 3, 153, 1, 73, 1, 0, 2, 197, 1, 36, 1, 0, 3, 255, 1, 0, 2, 36, 1, 197, 1, 0, 3, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 1, 153, 1, 255, 8, 0, 2, 153, 1, 73, 1, 0, 2, 153, 1, 73, 1, 0, 3, 197, 1, 36, 1, 0, 2, 255, 1, 0, 4, 255, 1, 0, 2, 36, 1, 197, 1, 0, 2, 153, 1, 255, 8, 0, 1, 111, 2, 0, 2, 153, 1, 73, 1, 0, 3, 153, 1, 73, 1, 0, 2, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 2, 255, 1, 0, 39, }; +static const unsigned char _37[] = { +0, 47, 153, 1, 255, 2, 73, 1, 0, 4, 197, 1, 73, 1, 0, 4, 73, 1, 255, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 2, 73, 1, 153, 1, 0, 5, 153, 1, 197, 1, 0, 2, 197, 1, 111, 1, 0, 2, 197, 1, 36, 1, 0, 5, 153, 2, 0, 2, 197, 1, 153, 1, 0, 1, 111, 2, 0, 6, 153, 2, 0, 2, 197, 1, 111, 1, 0, 1, 255, 1, 0, 7, 73, 1, 255, 1, 0, 1, 36, 1, 255, 1, 36, 1, 111, 2, 0, 1, 255, 3, 36, 1, 0, 3, 153, 1, 255, 2, 73, 1, 0, 1, 255, 1, 0, 1, 153, 1, 197, 1, 0, 1, 111, 1, 255, 1, 0, 7, 153, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 5, 36, 1, 197, 1, 0, 2, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 5, 153, 1, 73, 1, 0, 2, 255, 1, 111, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 4, 73, 1, 153, 1, 0, 3, 153, 1, 197, 1, 0, 1, 111, 1, 197, 1, 0, 5, 197, 1, 36, 1, 0, 4, 197, 1, 255, 2, 36, 1, 0, 61, }; +static const unsigned char _39[] = { +0, 10, 255, 1, 153, 1, 0, 1, 255, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 1, 197, 1, 73, 1, 0, 36, }; +static const unsigned char _40[] = { +0, 22, 153, 2, 0, 3, 111, 1, 197, 1, 0, 4, 255, 1, 36, 1, 0, 3, 153, 1, 197, 1, 0, 4, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 111, 1, 255, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 4, 255, 1, 111, 1, 0, 4, 153, 1, 197, 1, 0, 5, 255, 1, 73, 1, 0, 4, 111, 1, 197, 1, 0, 5, 153, 2, 0, 6, }; +static const unsigned char _41[] = { +0, 19, 111, 1, 197, 1, 0, 5, 153, 2, 0, 4, 36, 1, 255, 1, 36, 1, 0, 4, 153, 1, 197, 1, 0, 4, 73, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 4, 255, 1, 153, 1, 0, 4, 197, 1, 153, 1, 0, 4, 255, 1, 153, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 153, 2, 0, 3, 36, 1, 255, 1, 36, 1, 0, 3, 153, 2, 0, 3, 111, 1, 197, 1, 0, 9, }; +static const unsigned char _43[] = { +0, 54, 73, 1, 255, 1, 36, 1, 0, 7, 73, 1, 255, 1, 36, 1, 0, 7, 73, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 7, 111, 1, 0, 4, 73, 1, 255, 1, 36, 1, 0, 7, 73, 1, 255, 1, 36, 1, 0, 7, 73, 1, 255, 1, 36, 1, 0, 73, }; +static const unsigned char _44[] = { +0, 72, 255, 1, 153, 1, 0, 3, 36, 1, 153, 1, 0, 3, 111, 2, 0, 3, 197, 1, 0, 7, }; +static const unsigned char _45[] = { +0, 60, 36, 1, 255, 4, 197, 1, 0, 48, }; +static const unsigned char _46[] = { +0, 72, 255, 1, 153, 1, 0, 21, }; +static const unsigned char _47[] = { +0, 19, 255, 1, 0, 3, 73, 1, 153, 1, 0, 3, 153, 1, 73, 1, 0, 3, 255, 1, 0, 3, 73, 1, 153, 1, 0, 3, 153, 1, 111, 1, 0, 3, 197, 1, 36, 1, 0, 2, 36, 1, 197, 1, 0, 3, 111, 2, 0, 3, 197, 1, 36, 1, 0, 2, 36, 1, 197, 1, 0, 3, 111, 2, 0, 23, }; +static const unsigned char _48[] = { +0, 30, 255, 4, 0, 4, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 0, 4, 255, 1, 111, 1, 0, 1, 197, 2, 0, 4, 197, 2, 0, 1, 197, 1, 153, 1, 0, 4, 153, 1, 197, 1, 0, 1, 255, 1, 153, 1, 0, 4, 153, 1, 255, 1, 0, 1, 255, 1, 153, 1, 0, 4, 153, 1, 255, 1, 0, 1, 197, 1, 153, 1, 0, 4, 153, 1, 197, 1, 0, 1, 197, 2, 0, 4, 197, 1, 153, 1, 0, 1, 111, 1, 255, 1, 0, 4, 255, 1, 111, 1, 0, 2, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 4, 255, 4, 0, 38, }; +static const unsigned char _49[] = { +0, 32, 197, 1, 73, 1, 0, 6, 153, 1, 255, 1, 73, 1, 0, 5, 255, 3, 73, 1, 0, 4, 197, 2, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 38, }; +static const unsigned char _50[] = { +0, 29, 36, 1, 255, 4, 0, 3, 36, 1, 255, 1, 197, 1, 0, 2, 255, 2, 0, 2, 153, 1, 255, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 6, 73, 1, 255, 1, 73, 1, 0, 5, 36, 1, 255, 1, 197, 1, 0, 6, 255, 2, 0, 5, 36, 1, 255, 1, 197, 1, 0, 5, 73, 1, 255, 1, 197, 1, 0, 5, 36, 1, 255, 1, 153, 1, 0, 6, 197, 2, 0, 6, 36, 1, 255, 7, 111, 1, 0, 36, }; +static const unsigned char _51[] = { +0, 29, 73, 1, 255, 3, 111, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 2, 255, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 0, 7, 111, 1, 255, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 5, 255, 2, 197, 1, 0, 8, 153, 1, 255, 1, 36, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 7, 255, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 111, 1, 255, 1, 0, 3, 153, 1, 197, 1, 0, 3, 73, 1, 255, 3, 197, 1, 0, 38, }; +static const unsigned char _52[] = { +0, 32, 73, 1, 255, 1, 36, 1, 0, 6, 255, 2, 36, 1, 0, 5, 153, 1, 255, 2, 36, 1, 0, 4, 36, 1, 255, 1, 111, 1, 255, 1, 36, 1, 0, 4, 197, 1, 111, 1, 73, 1, 255, 1, 36, 1, 0, 3, 111, 1, 197, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 197, 1, 111, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 7, 111, 1, 0, 5, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 37, }; +static const unsigned char _53[] = { +0, 29, 153, 1, 255, 5, 0, 3, 255, 1, 111, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 73, 1, 255, 1, 0, 7, 111, 1, 197, 1, 255, 3, 197, 1, 0, 3, 153, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 8, 255, 1, 111, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 111, 1, 255, 1, 0, 3, 111, 1, 197, 1, 0, 3, 73, 1, 255, 3, 153, 1, 0, 38, }; +static const unsigned char _54[] = { +0, 30, 255, 4, 0, 4, 255, 1, 36, 1, 0, 2, 197, 1, 255, 1, 0, 2, 153, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 6, 36, 1, 255, 1, 73, 1, 153, 1, 255, 3, 0, 2, 36, 1, 255, 2, 111, 1, 0, 2, 111, 1, 255, 1, 0, 1, 36, 1, 255, 1, 197, 1, 0, 4, 255, 1, 111, 1, 36, 1, 255, 1, 111, 1, 0, 4, 255, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 4, 255, 1, 153, 1, 0, 1, 197, 2, 0, 4, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 111, 1, 197, 1, 0, 4, 255, 3, 197, 1, 0, 38, }; +static const unsigned char _55[] = { +0, 28, 197, 1, 255, 6, 153, 1, 0, 6, 153, 1, 255, 1, 36, 1, 0, 5, 73, 1, 255, 1, 111, 1, 0, 6, 197, 2, 0, 6, 73, 1, 255, 1, 73, 1, 0, 6, 153, 1, 255, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 153, 1, 255, 1, 0, 7, 197, 1, 153, 1, 0, 7, 255, 1, 111, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 40, }; +static const unsigned char _56[] = { +0, 30, 255, 4, 0, 4, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 2, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 36, 1, 0, 3, 197, 1, 255, 2, 197, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 73, 1, 0, 1, 197, 2, 0, 4, 153, 1, 197, 1, 0, 1, 255, 1, 153, 1, 0, 4, 111, 1, 255, 1, 0, 1, 197, 2, 0, 4, 153, 1, 197, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 4, 36, 1, 0, 37, }; +static const unsigned char _57[] = { +0, 29, 36, 1, 255, 3, 111, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 255, 1, 153, 1, 0, 2, 197, 2, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 255, 1, 153, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 197, 2, 0, 3, 73, 1, 255, 1, 153, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 255, 2, 153, 1, 0, 2, 73, 1, 255, 3, 36, 1, 197, 1, 111, 1, 0, 7, 255, 1, 73, 1, 0, 6, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 3, 197, 1, 255, 3, 73, 1, 0, 38, }; +static const unsigned char _58[] = { +0, 32, 255, 1, 153, 1, 0, 38, 255, 1, 153, 1, 0, 21, }; +static const unsigned char _59[] = { +0, 32, 255, 1, 153, 1, 0, 38, 255, 1, 153, 1, 0, 3, 36, 1, 153, 1, 0, 3, 111, 2, 0, 3, 197, 1, 0, 7, }; +static const unsigned char _60[] = { +0, 48, 153, 1, 73, 1, 0, 6, 153, 1, 255, 2, 73, 1, 0, 4, 153, 1, 255, 3, 36, 1, 0, 3, 153, 1, 255, 2, 111, 1, 0, 5, 153, 1, 255, 1, 0, 9, 153, 1, 255, 2, 111, 1, 0, 8, 153, 1, 255, 3, 36, 1, 0, 7, 153, 1, 255, 2, 73, 1, 0, 8, 153, 1, 73, 1, 0, 60, }; +static const unsigned char _61[] = { +0, 71, 153, 1, 255, 7, 73, 1, 0, 31, 153, 1, 255, 7, 73, 1, 0, 70, }; +static const unsigned char _62[] = { +0, 41, 153, 1, 73, 1, 0, 8, 153, 1, 255, 2, 73, 1, 0, 7, 111, 1, 255, 3, 73, 1, 0, 8, 197, 1, 255, 2, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 5, 197, 1, 255, 2, 73, 1, 0, 3, 111, 1, 255, 3, 73, 1, 0, 4, 153, 1, 255, 2, 73, 1, 0, 6, 153, 1, 73, 1, 0, 67, }; +static const unsigned char _63[] = { +0, 29, 36, 1, 255, 4, 0, 3, 36, 1, 255, 1, 111, 1, 0, 2, 197, 1, 255, 1, 0, 2, 153, 1, 197, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 153, 1, 0, 4, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 6, 197, 1, 255, 1, 0, 6, 197, 1, 255, 1, 36, 1, 0, 5, 153, 1, 255, 1, 36, 1, 0, 6, 255, 1, 153, 1, 0, 7, 255, 1, 111, 1, 0, 15, 73, 1, 255, 1, 111, 1, 0, 39, }; +static const unsigned char _64[] = { +0, 57, 153, 1, 255, 5, 73, 1, 0, 8, 111, 1, 255, 1, 153, 1, 0, 4, 36, 1, 255, 2, 36, 1, 0, 5, 153, 1, 255, 1, 0, 8, 111, 1, 255, 1, 0, 4, 73, 1, 255, 1, 0, 3, 255, 3, 36, 1, 197, 1, 153, 1, 0, 1, 153, 2, 0, 3, 197, 1, 111, 1, 0, 1, 36, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 2, 111, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 0, 2, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 73, 1, 0, 2, 255, 1, 73, 1, 0, 1, 111, 1, 153, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 2, 197, 1, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 111, 1, 255, 1, 0, 4, 111, 1, 255, 1, 0, 3, 255, 1, 36, 1, 0, 1, 153, 1, 111, 1, 0, 1, 153, 1, 255, 1, 0, 4, 197, 1, 153, 1, 0, 2, 73, 1, 255, 1, 0, 2, 153, 1, 111, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 255, 1, 73, 1, 0, 2, 111, 1, 197, 1, 0, 2, 255, 1, 153, 1, 0, 1, 36, 1, 255, 2, 73, 1, 0, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 2, 197, 1, 0, 1, 255, 3, 73, 1, 0, 5, 197, 1, 153, 1, 0, 10, 36, 1, 255, 1, 111, 1, 0, 3, 255, 1, 153, 1, 0, 9, 255, 1, 153, 1, 0, 5, 255, 2, 111, 1, 0, 5, 153, 1, 255, 1, 153, 1, 0, 8, 197, 1, 255, 5, 153, 1, 0, 4, }; +static const unsigned char _65[] = { +0, 37, 73, 1, 255, 2, 0, 8, 197, 1, 153, 1, 255, 1, 111, 1, 0, 6, 36, 1, 255, 1, 73, 1, 197, 2, 0, 6, 153, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 5, 255, 1, 153, 1, 0, 2, 255, 1, 153, 1, 0, 4, 73, 1, 255, 1, 73, 1, 0, 2, 153, 1, 255, 1, 0, 4, 197, 2, 0, 3, 73, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 7, 197, 1, 0, 2, 153, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 255, 1, 153, 1, 0, 5, 36, 1, 255, 1, 153, 1, 73, 1, 255, 1, 73, 1, 0, 6, 153, 1, 255, 1, 197, 2, 0, 7, 73, 1, 255, 1, 0, 44, }; +static const unsigned char _66[] = { +0, 34, 73, 1, 255, 6, 153, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 153, 1, 197, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 7, 73, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 197, 1, 255, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 255, 1, 197, 1, 0, 2, 73, 1, 255, 6, 153, 1, 0, 46, }; +static const unsigned char _67[] = { +0, 40, 153, 1, 255, 4, 36, 1, 0, 4, 36, 1, 255, 1, 197, 1, 0, 3, 111, 1, 255, 1, 111, 1, 0, 3, 197, 2, 0, 5, 153, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 36, 2, 0, 2, 153, 1, 255, 1, 36, 1, 0, 9, 153, 1, 255, 1, 0, 10, 153, 1, 255, 1, 0, 10, 111, 1, 255, 1, 36, 1, 0, 9, 73, 1, 255, 1, 73, 1, 0, 5, 36, 1, 255, 1, 153, 1, 0, 2, 197, 2, 0, 5, 111, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 197, 1, 0, 3, 111, 1, 255, 1, 111, 1, 0, 5, 197, 1, 255, 4, 36, 1, 0, 50, }; +static const unsigned char _68[] = { +0, 37, 73, 1, 255, 6, 197, 1, 0, 4, 73, 1, 255, 1, 73, 1, 0, 4, 197, 1, 255, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 5, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 153, 1, 255, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 5, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 255, 2, 0, 3, 73, 1, 255, 6, 153, 1, 0, 51, }; +static const unsigned char _69[] = { +0, 34, 73, 1, 255, 8, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 7, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 8, 111, 1, 0, 44, }; +static const unsigned char _70[] = { +0, 31, 73, 1, 255, 7, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 6, 73, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 46, }; +static const unsigned char _71[] = { +0, 40, 197, 1, 255, 4, 36, 1, 0, 4, 36, 1, 255, 1, 197, 1, 0, 3, 111, 1, 255, 1, 111, 1, 0, 3, 255, 1, 197, 1, 0, 5, 111, 1, 255, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 5, 36, 1, 153, 1, 36, 1, 0, 1, 153, 1, 255, 1, 0, 10, 197, 2, 0, 10, 197, 2, 0, 3, 73, 1, 255, 4, 111, 1, 0, 1, 153, 1, 255, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 5, 36, 1, 255, 1, 111, 1, 0, 2, 255, 1, 153, 1, 0, 5, 36, 1, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 197, 1, 0, 3, 73, 1, 255, 2, 36, 1, 0, 4, 153, 1, 255, 4, 73, 1, 0, 50, }; +static const unsigned char _72[] = { +0, 34, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 8, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 44, }; +static const unsigned char _73[] = { +0, 17, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 21, }; +static const unsigned char _74[] = { +0, 33, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 2, 255, 1, 111, 1, 0, 3, 197, 2, 0, 2, 255, 1, 153, 1, 0, 3, 197, 1, 153, 1, 0, 2, 111, 1, 255, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 3, 153, 1, 255, 3, 73, 1, 0, 38, }; +static const unsigned char _75[] = { +0, 34, 73, 1, 255, 1, 73, 1, 0, 4, 36, 1, 255, 2, 0, 1, 73, 1, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 111, 1, 0, 4, 73, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 5, 73, 1, 255, 1, 73, 1, 255, 2, 197, 1, 0, 5, 73, 1, 255, 2, 111, 2, 255, 1, 153, 1, 0, 4, 73, 1, 255, 1, 153, 1, 0, 2, 197, 1, 255, 1, 73, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 2, 0, 3, 73, 1, 255, 1, 73, 1, 0, 3, 111, 1, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 255, 2, 0, 44, }; +static const unsigned char _76[] = { +0, 28, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 6, 197, 1, 0, 36, }; +static const unsigned char _77[] = { +0, 40, 153, 1, 255, 1, 197, 1, 0, 5, 36, 1, 255, 2, 0, 2, 153, 1, 255, 2, 36, 1, 0, 4, 73, 1, 255, 2, 0, 2, 153, 1, 255, 1, 153, 1, 73, 1, 0, 4, 153, 2, 255, 1, 0, 2, 153, 1, 255, 1, 73, 1, 153, 1, 0, 4, 255, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 1, 255, 1, 0, 3, 73, 1, 153, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 1, 197, 1, 73, 1, 0, 2, 153, 1, 111, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 1, 111, 1, 153, 1, 0, 2, 255, 1, 36, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 1, 36, 1, 255, 1, 0, 1, 73, 1, 197, 1, 0, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 2, 197, 1, 73, 1, 153, 1, 111, 1, 0, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 2, 153, 1, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 2, 73, 1, 255, 1, 197, 1, 0, 2, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 3, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 0, 53, }; +static const unsigned char _78[] = { +0, 34, 111, 1, 255, 1, 111, 1, 0, 4, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 2, 0, 4, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 153, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 1, 153, 2, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 2, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 2, 111, 1, 197, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 255, 1, 73, 2, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 197, 1, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 4, 197, 2, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 4, 73, 1, 255, 2, 36, 1, 0, 1, 111, 1, 255, 1, 0, 5, 153, 1, 255, 1, 36, 1, 0, 44, }; +static const unsigned char _79[] = { +0, 40, 255, 4, 153, 1, 0, 5, 73, 1, 255, 1, 153, 1, 0, 3, 255, 2, 0, 4, 255, 1, 153, 1, 0, 5, 255, 1, 153, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 1, 153, 1, 255, 1, 0, 6, 73, 1, 255, 1, 73, 1, 0, 1, 197, 2, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 197, 2, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 153, 1, 255, 1, 0, 6, 73, 1, 255, 1, 73, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 2, 255, 1, 153, 1, 0, 5, 255, 1, 153, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 3, 255, 2, 0, 6, 197, 1, 255, 3, 111, 1, 0, 51, }; +static const unsigned char _80[] = { +0, 34, 73, 1, 255, 7, 36, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 36, 1, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 255, 1, 153, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 36, 1, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 197, 1, 255, 1, 0, 2, 73, 1, 255, 7, 0, 3, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 51, }; +static const unsigned char _81[] = { +0, 40, 255, 4, 111, 1, 0, 5, 111, 1, 255, 1, 111, 1, 0, 3, 255, 2, 0, 3, 36, 1, 255, 1, 111, 1, 0, 5, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 6, 111, 1, 255, 1, 36, 1, 0, 1, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 153, 1, 255, 1, 0, 6, 111, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 36, 1, 255, 1, 197, 1, 0, 3, 111, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 2, 36, 1, 0, 5, 255, 7, 73, 1, 0, 10, 73, 1, 111, 1, 0, 36, }; +static const unsigned char _82[] = { +0, 34, 111, 1, 255, 6, 197, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 111, 1, 255, 6, 153, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 2, 153, 1, 255, 1, 36, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 197, 1, 255, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 1, 73, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 5, 255, 2, 0, 44, }; +static const unsigned char _83[] = { +0, 36, 153, 1, 255, 4, 73, 1, 0, 4, 255, 1, 197, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 9, 255, 2, 36, 1, 0, 9, 255, 4, 111, 1, 0, 9, 153, 1, 255, 2, 111, 1, 0, 9, 111, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 6, 255, 1, 111, 1, 0, 1, 153, 1, 255, 1, 0, 5, 36, 1, 255, 1, 73, 1, 0, 2, 255, 2, 36, 1, 0, 3, 255, 1, 197, 1, 0, 4, 153, 1, 255, 4, 111, 1, 0, 46, }; +static const unsigned char _84[] = { +0, 27, 255, 9, 0, 4, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 39, }; +static const unsigned char _85[] = { +0, 34, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 4, 153, 1, 197, 1, 0, 3, 153, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 111, 1, 255, 4, 36, 1, 0, 46, }; +static const unsigned char _86[] = { +0, 33, 111, 1, 255, 1, 73, 1, 0, 6, 111, 1, 255, 1, 0, 1, 255, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 1, 153, 1, 255, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 4, 153, 1, 197, 1, 0, 3, 197, 1, 153, 1, 0, 4, 255, 1, 111, 1, 0, 3, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 2, 153, 2, 0, 5, 153, 2, 0, 1, 36, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 36, 1, 111, 1, 255, 1, 0, 7, 255, 1, 111, 1, 197, 1, 111, 1, 0, 7, 111, 1, 255, 2, 36, 1, 0, 7, 36, 1, 255, 1, 197, 1, 0, 48, }; +static const unsigned char _87[] = { +0, 51, 73, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 2, 0, 5, 153, 1, 255, 1, 0, 1, 255, 1, 153, 1, 0, 4, 153, 1, 255, 2, 73, 1, 0, 4, 255, 1, 153, 1, 0, 1, 197, 2, 0, 4, 255, 1, 111, 1, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 73, 1, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 2, 197, 2, 0, 3, 197, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 2, 255, 1, 111, 1, 0, 2, 255, 1, 111, 1, 0, 3, 153, 1, 197, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 153, 1, 197, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 111, 1, 255, 1, 0, 5, 255, 1, 73, 1, 153, 1, 197, 1, 0, 4, 255, 1, 73, 1, 197, 1, 153, 1, 0, 5, 197, 1, 153, 1, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 255, 1, 73, 1, 0, 5, 111, 1, 255, 2, 36, 1, 0, 4, 111, 1, 255, 2, 0, 6, 36, 1, 255, 1, 197, 1, 0, 5, 36, 1, 255, 1, 153, 1, 0, 71, }; +static const unsigned char _88[] = { +0, 34, 197, 1, 255, 1, 36, 1, 0, 4, 36, 1, 255, 1, 197, 1, 0, 2, 255, 1, 197, 1, 0, 4, 197, 2, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 1, 36, 2, 255, 1, 73, 1, 0, 6, 197, 1, 153, 1, 197, 1, 153, 1, 0, 7, 36, 1, 255, 1, 197, 1, 0, 8, 111, 1, 255, 2, 73, 1, 0, 6, 73, 1, 255, 1, 73, 1, 153, 1, 255, 1, 36, 1, 0, 5, 255, 1, 153, 1, 0, 2, 255, 1, 197, 1, 0, 4, 197, 1, 255, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 36, 1, 111, 1, 255, 1, 153, 1, 0, 6, 255, 2, 0, 44, }; +static const unsigned char _89[] = { +0, 33, 111, 1, 255, 1, 153, 1, 0, 5, 36, 1, 255, 2, 0, 1, 153, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 36, 1, 0, 2, 255, 2, 0, 3, 73, 1, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 153, 1, 0, 2, 197, 2, 0, 5, 153, 1, 255, 1, 36, 1, 111, 1, 255, 1, 36, 1, 0, 6, 255, 3, 111, 1, 0, 7, 73, 1, 255, 1, 197, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 48, }; +static const unsigned char _90[] = { +0, 28, 153, 1, 255, 6, 197, 1, 0, 6, 73, 1, 255, 1, 111, 1, 0, 6, 255, 1, 197, 1, 0, 6, 111, 1, 255, 1, 36, 1, 0, 5, 36, 1, 255, 1, 111, 1, 0, 6, 197, 2, 0, 6, 111, 1, 255, 1, 36, 1, 0, 5, 36, 1, 255, 1, 111, 1, 0, 6, 197, 2, 0, 6, 73, 1, 255, 1, 73, 1, 0, 6, 255, 1, 153, 1, 0, 6, 73, 1, 255, 8, 0, 36, }; +static const unsigned char _91[] = { +0, 16, 111, 1, 255, 2, 153, 1, 0, 1, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 2, 153, 1, 0, 5, }; +static const unsigned char _93[] = { +0, 16, 255, 3, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 255, 3, 36, 1, 0, 5, }; +static const unsigned char _95[] = { +0, 153, 197, 1, 255, 8, 0, 9, }; +static const unsigned char _97[] = { +0, 56, 73, 1, 255, 4, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 111, 1, 255, 1, 0, 2, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 4, 111, 1, 255, 3, 73, 1, 0, 1, 73, 1, 255, 3, 73, 1, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 3, 111, 1, 255, 1, 73, 1, 0, 1, 197, 1, 255, 1, 0, 2, 36, 1, 255, 2, 73, 1, 0, 2, 255, 4, 36, 1, 255, 1, 111, 1, 0, 36, }; +static const unsigned char _98[] = { +0, 28, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 153, 1, 255, 2, 197, 1, 0, 3, 153, 1, 255, 1, 153, 1, 0, 2, 197, 2, 0, 2, 153, 1, 255, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 153, 2, 0, 4, 197, 1, 153, 1, 0, 1, 153, 2, 0, 4, 197, 1, 153, 1, 0, 1, 153, 2, 0, 4, 255, 1, 111, 1, 0, 1, 153, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 153, 1, 255, 1, 111, 1, 0, 2, 197, 2, 0, 2, 153, 3, 255, 2, 197, 1, 0, 38, }; +static const unsigned char _99[] = { +0, 56, 36, 1, 255, 3, 111, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 153, 1, 255, 1, 0, 3, 153, 1, 197, 1, 0, 2, 197, 1, 153, 1, 0, 7, 197, 1, 153, 1, 0, 7, 197, 1, 153, 1, 0, 7, 153, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 2, 255, 1, 111, 1, 0, 3, 36, 1, 255, 3, 111, 1, 0, 38, }; +static const unsigned char _100[] = { +0, 33, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 3, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 36, 1, 0, 1, 197, 1, 153, 1, 0, 3, 73, 1, 255, 1, 36, 2, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 36, 2, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 36, 2, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 36, 1, 0, 1, 197, 1, 153, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 255, 2, 36, 1, 0, 2, 73, 1, 255, 3, 111, 1, 255, 1, 36, 1, 0, 36, }; +static const unsigned char _101[] = { +0, 56, 36, 1, 255, 3, 197, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 2, 197, 2, 0, 2, 197, 2, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 36, 1, 255, 7, 153, 1, 0, 1, 255, 1, 111, 1, 0, 7, 197, 2, 0, 4, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 153, 1, 255, 1, 0, 3, 36, 1, 255, 4, 0, 38, }; +static const unsigned char _102[] = { +0, 17, 73, 1, 255, 2, 0, 2, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 1, 73, 1, 255, 4, 0, 2, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 21, }; +static const unsigned char _103[] = { +0, 56, 73, 1, 255, 3, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 36, 1, 0, 1, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 36, 2, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 2, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 36, 2, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 36, 1, 0, 2, 73, 1, 255, 3, 111, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 0, 2, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 2, 36, 1, 255, 4, 111, 1, 0, 11, }; +static const unsigned char _104[] = { +0, 28, 111, 1, 255, 1, 0, 7, 111, 1, 255, 1, 0, 7, 111, 1, 255, 1, 0, 7, 111, 1, 255, 1, 111, 1, 255, 3, 36, 1, 0, 2, 111, 1, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 36, }; +static const unsigned char _105[] = { +0, 13, 73, 1, 255, 1, 36, 1, 0, 9, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 16, }; +static const unsigned char _106[] = { +0, 10, 255, 1, 111, 1, 0, 7, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 36, 1, 255, 1, 73, 1, 255, 1, 197, 1, 0, 4, }; +static const unsigned char _107[] = { +0, 25, 197, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 2, 73, 1, 255, 1, 197, 1, 0, 1, 197, 1, 153, 1, 0, 2, 255, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 3, 197, 1, 153, 2, 255, 1, 0, 4, 197, 1, 255, 1, 111, 1, 255, 1, 111, 1, 0, 3, 197, 2, 0, 1, 153, 1, 255, 1, 36, 1, 0, 2, 197, 1, 153, 1, 0, 2, 255, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 2, 111, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 197, 1, 255, 1, 0, 32, }; +static const unsigned char _108[] = { +0, 10, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 12, }; +static const unsigned char _109[] = { +0, 79, 197, 1, 153, 2, 255, 2, 153, 1, 0, 1, 255, 3, 111, 1, 0, 2, 197, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 2, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 1, 197, 2, 0, 3, 255, 1, 153, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 52, }; +static const unsigned char _110[] = { +0, 55, 111, 1, 197, 1, 73, 1, 255, 3, 36, 1, 0, 2, 111, 1, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 36, }; +static const unsigned char _111[] = { +0, 56, 36, 1, 255, 3, 197, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 197, 2, 0, 2, 197, 2, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 4, 255, 1, 153, 1, 0, 1, 197, 2, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 197, 1, 255, 1, 0, 3, 36, 1, 255, 3, 197, 1, 0, 38, }; +static const unsigned char _112[] = { +0, 55, 153, 3, 255, 2, 197, 1, 0, 3, 153, 1, 255, 1, 153, 1, 0, 2, 197, 2, 0, 2, 153, 1, 255, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 153, 2, 0, 4, 255, 1, 111, 1, 0, 1, 153, 2, 0, 4, 255, 1, 153, 1, 0, 1, 153, 2, 0, 4, 255, 1, 111, 1, 0, 1, 153, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 153, 1, 255, 1, 111, 1, 0, 2, 255, 1, 197, 1, 0, 2, 153, 1, 197, 2, 255, 2, 153, 1, 0, 3, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 0, 15, }; +static const unsigned char _113[] = { +0, 56, 73, 1, 255, 3, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 73, 1, 36, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 197, 2, 0, 3, 111, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 2, 73, 1, 0, 2, 36, 1, 255, 3, 111, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 9, }; +static const unsigned char _114[] = { +0, 37, 73, 1, 255, 1, 111, 1, 255, 2, 0, 1, 73, 1, 255, 1, 197, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 26, }; +static const unsigned char _115[] = { +0, 50, 255, 4, 73, 1, 0, 2, 197, 1, 153, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 1, 255, 1, 73, 1, 0, 6, 197, 1, 255, 1, 153, 1, 0, 6, 111, 1, 255, 3, 153, 1, 0, 6, 111, 1, 255, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 4, 111, 1, 0, 33, }; +static const unsigned char _116[] = { +0, 13, 36, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 1, 197, 1, 255, 3, 0, 1, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 36, 1, 255, 2, 0, 16, }; +static const unsigned char _117[] = { +0, 55, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 2, 255, 2, 36, 1, 0, 2, 111, 1, 255, 3, 36, 1, 255, 1, 36, 1, 0, 36, }; +static const unsigned char _118[] = { +0, 42, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 255, 1, 0, 3, 36, 1, 255, 1, 36, 1, 255, 1, 73, 1, 0, 2, 111, 1, 255, 1, 0, 1, 197, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 1, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 73, 1, 153, 1, 197, 1, 0, 3, 197, 1, 153, 1, 255, 1, 111, 1, 0, 3, 73, 1, 255, 2, 36, 1, 0, 4, 255, 1, 197, 1, 0, 30, }; +static const unsigned char _119[] = { +0, 66, 111, 1, 255, 1, 0, 3, 255, 1, 197, 1, 0, 2, 73, 1, 255, 1, 36, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 0, 2, 111, 1, 197, 1, 0, 1, 255, 1, 111, 1, 0, 1, 73, 1, 153, 1, 255, 1, 36, 1, 0, 1, 197, 1, 111, 1, 0, 1, 153, 1, 197, 1, 0, 1, 153, 1, 111, 1, 197, 1, 73, 1, 0, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 0, 1, 197, 1, 73, 1, 153, 2, 73, 1, 255, 1, 0, 2, 36, 1, 255, 1, 36, 1, 255, 1, 36, 1, 111, 1, 197, 1, 111, 1, 153, 1, 0, 3, 197, 3, 0, 1, 36, 1, 255, 1, 197, 1, 111, 1, 0, 3, 153, 1, 255, 1, 153, 1, 0, 2, 255, 2, 36, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 197, 1, 255, 1, 0, 46, }; +static const unsigned char _120[] = { +0, 42, 36, 1, 255, 1, 111, 1, 0, 2, 153, 1, 197, 1, 0, 1, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 255, 1, 111, 1, 197, 1, 111, 1, 0, 3, 73, 1, 255, 2, 0, 5, 255, 1, 153, 1, 0, 4, 111, 1, 255, 2, 73, 1, 0, 2, 36, 1, 255, 1, 73, 1, 153, 1, 197, 1, 0, 2, 153, 2, 0, 2, 255, 1, 73, 2, 255, 1, 36, 1, 0, 2, 111, 1, 255, 1, 0, 28, }; +static const unsigned char _121[] = { +0, 54, 36, 1, 255, 1, 111, 1, 0, 4, 153, 1, 255, 1, 0, 1, 197, 2, 0, 4, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 255, 1, 153, 1, 0, 2, 153, 2, 0, 3, 111, 1, 255, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 73, 1, 111, 1, 197, 1, 0, 5, 197, 1, 153, 1, 197, 1, 111, 1, 0, 5, 73, 1, 255, 2, 36, 1, 0, 6, 255, 1, 153, 1, 0, 7, 255, 1, 73, 1, 0, 6, 111, 1, 197, 1, 0, 5, 153, 1, 255, 2, 0, 14, }; +static const unsigned char _122[] = { +0, 49, 255, 6, 153, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 4, 73, 1, 255, 1, 111, 1, 0, 5, 255, 1, 153, 1, 0, 5, 197, 1, 255, 1, 0, 5, 111, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 1, 111, 1, 0, 5, 255, 1, 197, 1, 0, 5, 111, 1, 255, 7, 0, 32, }; +static const unsigned char _14849714[] = { +0, 59, 36, 1, 0, 16, 197, 1, 73, 1, 0, 14, 73, 1, 255, 1, 197, 1, 0, 14, 197, 1, 255, 2, 73, 1, 0, 12, 73, 1, 255, 3, 197, 1, 0, 12, 197, 1, 255, 4, 73, 1, 0, 10, 73, 1, 255, 5, 197, 1, 0, 10, 197, 1, 255, 6, 73, 1, 0, 8, 73, 1, 255, 7, 197, 1, 0, 8, 197, 1, 255, 8, 73, 1, 0, 6, 73, 1, 255, 9, 197, 1, 0, 6, 255, 11, 111, 1, 0, 70, }; +static const unsigned char _14849724[] = { +0, 53, 36, 1, 255, 11, 153, 1, 0, 5, 153, 1, 255, 10, 36, 1, 0, 5, 36, 1, 255, 9, 153, 1, 0, 7, 153, 1, 255, 8, 36, 1, 0, 7, 36, 1, 255, 7, 153, 1, 0, 9, 153, 1, 255, 6, 36, 1, 0, 9, 36, 1, 255, 5, 153, 1, 0, 11, 153, 1, 255, 4, 36, 1, 0, 11, 36, 1, 255, 3, 153, 1, 0, 13, 153, 1, 255, 2, 36, 1, 0, 13, 36, 1, 255, 1, 153, 1, 0, 15, 153, 1, 36, 1, 0, 75, }; +static LATTICE lattice_array[] = { + {32, 5, _32}, + {33, 5, _33}, + {35, 9, _35}, + {37, 15, _37}, + {39, 3, _39}, + {40, 6, _40}, + {41, 6, _41}, + {43, 10, _43}, + {44, 5, _44}, + {45, 6, _45}, + {46, 5, _46}, + {47, 5, _47}, + {48, 9, _48}, + {49, 9, _49}, + {50, 9, _50}, + {51, 9, _51}, + {52, 9, _52}, + {53, 9, _53}, + {54, 9, _54}, + {55, 9, _55}, + {56, 9, _56}, + {57, 9, _57}, + {58, 5, _58}, + {59, 5, _59}, + {60, 10, _60}, + {61, 10, _61}, + {62, 10, _62}, + {63, 9, _63}, + {64, 17, _64}, + {65, 11, _65}, + {66, 11, _66}, + {67, 12, _67}, + {68, 12, _68}, + {69, 11, _69}, + {70, 10, _70}, + {71, 12, _71}, + {72, 11, _72}, + {73, 5, _73}, + {74, 9, _74}, + {75, 11, _75}, + {76, 9, _76}, + {77, 13, _77}, + {78, 11, _78}, + {79, 12, _79}, + {80, 11, _80}, + {81, 12, _81}, + {82, 11, _82}, + {83, 11, _83}, + {84, 9, _84}, + {85, 11, _85}, + {86, 11, _86}, + {87, 17, _87}, + {88, 11, _88}, + {89, 11, _89}, + {90, 9, _90}, + {91, 5, _91}, + {93, 5, _93}, + {95, 9, _95}, + {97, 9, _97}, + {98, 9, _98}, + {99, 9, _99}, + {100, 9, _100}, + {101, 9, _101}, + {102, 5, _102}, + {103, 9, _103}, + {104, 9, _104}, + {105, 4, _105}, + {106, 3, _106}, + {107, 8, _107}, + {108, 3, _108}, + {109, 13, _109}, + {110, 9, _110}, + {111, 9, _111}, + {112, 9, _112}, + {113, 9, _113}, + {114, 6, _114}, + {115, 8, _115}, + {116, 4, _116}, + {117, 9, _117}, + {118, 7, _118}, + {119, 11, _119}, + {120, 7, _120}, + {121, 9, _121}, + {122, 8, _122}, + {14849714, 17, _14849714}, + {14849724, 17, _14849724}, +}; +extern const LATTICE_FONT_INFO Arial_19_GL; +const LATTICE_FONT_INFO Arial_19_GL ={ + 19, + 86, + lattice_array +}; diff --git a/src/tft/tft.cpp b/src/tft/tft.cpp index adab410e..c9bd47ac 100644 --- a/src/tft/tft.cpp +++ b/src/tft/tft.cpp @@ -1,26 +1,24 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include -#include -#include "USBHost_t36.h" +#include #include "usb64_conf.h" +#include "n64_wrapper.h" #include "n64_controller.h" #include "input.h" #include "memory.h" #include "printf.h" -#include "ILI9341_t3n.h" #include "tft.h" #include "fileio.h" -#if (ENABLE_TFT_DISPLAY >= 1) +#define GUILITE_ON +#include "GuiLite.h" + #include "controller_icon.h" #include "usb64_logo.h" -#include "ili9341_t3n_font_Arial.h" -ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO); -DMAMEM uint16_t _framebuffer[320 * 240]; static uint8_t _tft_page = 0; +static uint8_t _tft_page_changed = 1; static uint8_t _tft_max_pages = 2; static uint8_t _tft_update_needed = 0; @@ -30,271 +28,261 @@ static char *_tft_log_text_lines[_tft_log_max_lines]; extern n64_input_dev_t n64_in_dev[MAX_CONTROLLERS]; extern n64_transferpak n64_tpak[MAX_CONTROLLERS]; -extern float tempmonGetTemp(void); +extern n64_input_dev_t n64_in_dev[MAX_CONTROLLERS]; +extern n64_transferpak n64_tpak[MAX_CONTROLLERS]; + +static char text_buff[32]; + +#define BG_COLOR GL_RGB(16, 20, 16) +extern const LATTICE_FONT_INFO Arial_14_GL; +extern const LATTICE_FONT_INFO Arial_19_GL; +static c_surface *psurface; +static c_display *pdisplay; +static c_label n64_status; +static c_label fileio_status; +static c_label extram_size; +static c_label controller_status[4]; +static c_label controller_id[4]; +static c_label tft_log[_tft_log_max_lines]; static const char *n64_peri_to_string(n64_input_dev_t *c) { static char text_buff[32]; - //Handle some specific cases if (input_is_connected(c->id) == 0) { - tft.setTextColor(ILI9341_WHITE); return "NOT CONNECTED"; } if (c->type == N64_MOUSE) { - tft.setTextColor(ILI9341_GREEN); return "N64 MOUSE"; } if (c->type == N64_RANDNET) { - tft.setTextColor(ILI9341_GREEN); return "N64 RANDNET"; } if (input_is_dualstick_mode(c->id)) { - tft.setTextColor(ILI9341_GREEN); return "DUAL STICK MODE"; } switch (c->current_peripheral) { case PERI_NONE: - tft.setTextColor(ILI9341_WHITE); return "NO PERIPHERAL"; - case PERI_RUMBLE: - tft.setTextColor(ILI9341_GREEN); return "RUMBLE PAK"; - case PERI_MEMPAK: - tft.setTextColor(ILI9341_GREEN); if (c->mempack->virtual_is_active) return "VIRTUAL PAK"; - snprintf(text_buff, sizeof(text_buff), "MPAK (BANK %u)", c->mempack->id); + snprintf(text_buff, sizeof(text_buff), "MPAK (BANK %lu)", c->mempack->id); return text_buff; - case PERI_TPAK: - tft.setTextColor(ILI9341_GREEN); snprintf(text_buff, sizeof(text_buff), "TPAK (%s)", (c->tpak->gbcart->rom == NULL) ? "NO ROM" : c->tpak->gbcart->title); return text_buff; - default: - tft.setTextColor(ILI9341_RED); return "UNKNOWN"; } } -static void write_controller_status(int controller, int line, const char *text) -{ - const int x_margin = 50; - const int y_margin = 30; - const int text_height = 14; - const int line_padding = 2; - const int controller_padding = 22; - - //Clear old text - tft.fillRect(x_margin, y_margin + text_height + controller_padding * controller + (controller * 2 + line) * text_height + line_padding * line, - tft.width() - x_margin, - text_height + 2, BG_COLOUR); - - //Draw new text - tft.setCursor(x_margin, y_margin + text_height + controller_padding * controller + - (controller * 2 + line) * text_height + line_padding * line); - - tft.print(text); -} -#endif - void tft_init() { -#if (ENABLE_TFT_DISPLAY >= 1) - tft.begin(); - tft.setRotation(TFT_ROTATION); - tft.setFrameBuffer(_framebuffer); - tft.useFrameBuffer(true); + tft_dev_init(); + + static c_surface surface(TFT_WIDTH, TFT_HEIGHT, 2, Z_ORDER_LEVEL_0); + static c_display display(tft_dev_get_fb(), TFT_WIDTH, TFT_HEIGHT, &surface); + psurface = &surface; + pdisplay = &display; + + surface.fill_rect(0, 0, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); + + static c_image usb64_image; + memset(&usb64_image, 0, sizeof(c_image)); + BITMAP_INFO _image; + _image.color_bits = 16; + _image.height = 35; + _image.width = 120; + _image.pixel_color_array = usb64_logo; + usb64_image.draw_image(psurface, Z_ORDER_LEVEL_0, &_image, 0, 0, BG_COLOR); + + //Draw RAM status + snprintf(text_buff, sizeof(text_buff), "Detected RAM: %uMB", memory_get_ext_ram_size()); + extram_size.set_surface(psurface); + extram_size.set_bg_color(BG_COLOR); + extram_size.set_font_color(GL_RGB(255, 255, 255)); + extram_size.set_wnd_pos(125, 0, 1, Arial_14_GL.height); + extram_size.set_font_type(&Arial_14_GL); + extram_size.set_str(text_buff); + extram_size.show_window(); tft_force_update(); -#endif } void tft_try_update() { -#if (ENABLE_TFT_DISPLAY >= 1) - #if (0) - //Dump the framebuffer to a file on the SD Card, 10 seconds after power up. + //Dump the framebuffer to a file on the SD Card, 10 seconds after power up. Assuming 16bit display. //Convert to png with //ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb565le -s 320x240 -i tft_dump.bin -f image2 -vcodec png tft_dump.png if (millis() > 10000) { - fileio_write_to_file("tft_dump.bin", (uint8_t *)_framebuffer, sizeof(_framebuffer)); - while (1); + fileio_write_to_file("tft_dump.bin", (uint8_t *)tft_dev_get_fb(), TFT_WIDTH * TFT_HEIGHT * 2); + debug_print_status("TFT framebuffer dumped\n"); + while (1) yield(); } #endif if (_tft_update_needed == 0) + { return; + } - if (tft.asyncUpdateActive()) + if (tft_dev_is_busy()) + { return; + } tft_force_update(); -#endif } uint8_t tft_change_page(uint8_t page) { -#if (ENABLE_TFT_DISPLAY >= 1) - (page >= _tft_max_pages) ? _tft_page = 0 : _tft_page = page; + _tft_page = (_tft_page + 1) % _tft_max_pages; + _tft_page_changed = 1; return _tft_page; -#else - return 0; -#endif } void tft_force_update() { -#if (ENABLE_TFT_DISPLAY >= 1) - static int8_t current_page = -1; - char text_buff[64]; - uint8_t page_changed = 0; - - while (tft.asyncUpdateActive()); - - if (_tft_page != current_page) + //These are drawn once when the TFT page has changed. + if (_tft_page_changed) { - page_changed = 1; - current_page = _tft_page; - } - - /* Draw static elements for page */ - if (page_changed) - { - tft.fillScreen(BG_COLOUR); - - //Draw usb64 logo - tft.writeRect(0, 0, 120, 35, (uint16_t *)usb64_logo); - - tft.setFont(Arial_8); - - //Write the detected external ram - tft.setTextColor(ILI9341_WHITE); - snprintf(text_buff, sizeof(text_buff), "Detected RAM: %uMB", memory_get_ext_ram_size()); - tft.setCursor(125, 0); - tft.print(text_buff); - - //Write the detected SD card size - uint32_t sd_size = SD.totalSize() / 1024 / 1024; - if (sd_size == 0) - tft.setTextColor(ILI9341_RED); - snprintf(text_buff, sizeof(text_buff), "SD: %uMiB", sd_size); - tft.setCursor(125, 10); - tft.print(text_buff); - - //Write the current page number - tft.setTextColor(ILI9341_WHITE); - snprintf(text_buff, sizeof(text_buff), "%u/%u", _tft_page + 1, _tft_max_pages); - tft.setCursor(tft.width() - 10 * 6, 10); - tft.print(text_buff); - - tft.setTextColor(ILI9341_WHITE); - - switch (_tft_page) + _tft_page_changed = 0; + if (_tft_page == 0) { - case 0: - //Draw the four controller images - tft.writeRect(0, 40, 48, 45, (uint16_t *)controller_icon); - tft.writeRect(0, 90, 48, 45, (uint16_t *)controller_icon); - tft.writeRect(0, 140, 48, 45, (uint16_t *)controller_icon); - tft.writeRect(0, 190, 48, 45, (uint16_t *)controller_icon); - break; - case 1: - break; + psurface->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); + static c_image controller_image; + BITMAP_INFO _image; + memset(&controller_image, 0, sizeof(c_image)); + _image.color_bits = 16; + _image.height = 45; + _image.width = 48; + _image.pixel_color_array = controller_icon; + controller_image.draw_image(psurface, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 0 / 4), BG_COLOR); + controller_image.draw_image(psurface, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 1 / 4), BG_COLOR); + controller_image.draw_image(psurface, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 2 / 4), BG_COLOR); + controller_image.draw_image(psurface, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 3 / 4), BG_COLOR); + } + else if (_tft_page == 1) + { + psurface->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); } } - /* Draw dynamic elements for each page */ - //Draw N64 sense status - tft.setFont(Arial_8); - tft.setCursor(tft.width() - 10 * 6, 0); - tft.fillRect(tft.getCursorX(), tft.getCursorY(), tft.width() - tft.getCursorX(), 8, BG_COLOUR); - if (digitalRead(N64_CONSOLE_SENSE) == 0) - { - tft.setTextColor(ILI9341_RED); - tft.print("N64 is OFF"); - } - else - { - tft.setTextColor(ILI9341_GREEN); - tft.print("N64 is ON"); - } - - //Write Teensy temperature - tft.setTextColor(ILI9341_WHITE); - snprintf(text_buff, sizeof(text_buff), "%i°C", (int32_t)tempmonGetTemp()); - tft.setCursor(125, 20); - tft.fillRect(tft.getCursorX(), tft.getCursorY(), tft.width() - tft.getCursorX(), 8, BG_COLOUR); - tft.print(text_buff); - - //These elements are present on specific pages only. - switch (_tft_page) + //Draw dynamic items here. There are drawn everytime a TFT update is flagged. + if (_tft_page == 0) { - case 0: - //Print controller status screen - tft.setFont(Arial_13); - for (uint32_t i = 0; i < MAX_CONTROLLERS; i++) + //Draw controller status and peripheral type + for (int i = 0; i < 4; i++) { - snprintf(text_buff, sizeof(text_buff), "0x%04x/0x%04x\n", - input_get_id_vendor(i), - input_get_id_product(i)); - - write_controller_status(i, 0, n64_peri_to_string(&n64_in_dev[i])); - write_controller_status(i, 1, text_buff); + uint32_t colour = input_is_connected(i) ? GL_RGB(0, 255, 0) : GL_RGB(255, 255, 255); + controller_status[i].set_surface(psurface); + controller_status[i].set_bg_color(BG_COLOR); + controller_status[i].set_font_color(colour); + controller_status[i].set_wnd_pos(50, (45 + 0) + ((TFT_HEIGHT - 45) * i / 4), TFT_WIDTH, Arial_19_GL.height); + controller_status[i].set_font_type(&Arial_19_GL); + controller_status[i].set_str(n64_peri_to_string(&n64_in_dev[i])); + controller_status[i].show_window(); + + snprintf(text_buff, sizeof(text_buff), "0x%04x/0x%04x", input_get_id_vendor(i), input_get_id_product(i)); + controller_id[i].set_surface(psurface); + controller_id[i].set_font_color(colour); + controller_id[i].set_bg_color(BG_COLOR); + controller_id[i].set_wnd_pos(50, (45 + 20) + ((TFT_HEIGHT - 45) * i / 4), TFT_WIDTH, Arial_19_GL.height); + controller_id[i].set_font_type(&Arial_19_GL); + controller_id[i].set_str(text_buff); + controller_id[i].show_window(); } - break; - case 1: - //Print the debug log screen - tft.fillRect(0, 40, tft.width(), tft.height() - 40, BG_COLOUR); - tft.setTextColor(ILI9341_WHITE); - tft.setCursor(0, 40); - for (uint32_t i = 0; i < _tft_log_max_lines; i++) + } + else if (_tft_page == 1) + { + psurface->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); + for (int i = 0; i < _tft_log_max_lines; i++) { if (_tft_log_text_lines[i] == NULL) break; - tft.print(_tft_log_text_lines[i]); + tft_log[i].set_surface(psurface); + tft_log[i].set_bg_color(BG_COLOR); + tft_log[i].set_font_color(GL_RGB(255, 255, 255)); + tft_log[i].set_wnd_pos(0, 45 + i * Arial_14_GL.height, TFT_WIDTH, Arial_14_GL.height); + tft_log[i].set_font_type(&Arial_14_GL); + tft_log[i].set_str(_tft_log_text_lines[i]); + tft_log[i].show_window(); } + } - break; + //Draw N64 console status + uint32_t colour; + const char *n64_status_text; + if (n64hal_input_read(N64_CONSOLE_SENSE) == 0) + { + n64_status_text = "N64 is OFF"; + colour = GL_RGB(255, 0, 0); } - tft.updateScreenAsync(); - _tft_update_needed = 0; -#endif + else + { + n64_status_text = "N64 is ON"; + colour = GL_RGB(0, 255, 0); + } + n64_status.set_surface(psurface); + n64_status.set_bg_color(BG_COLOR); + n64_status.set_font_color(colour); + n64_status.set_wnd_pos(TFT_WIDTH - (10 * 8), 0, 100, Arial_14_GL.height); + n64_status.set_font_type(&Arial_14_GL); + n64_status.set_str(n64_status_text); + n64_status.show_window(); + + //Draw SD Card status + const char *fileio_status_text; + if (fileio_detected() == 0) + { + fileio_status_text = "SD Not Detected"; + colour = GL_RGB(255, 0, 0); + } + else + { + fileio_status_text = "SD Detected"; + colour = GL_RGB(0, 255, 0); + } + n64_status.set_surface(psurface); + n64_status.set_bg_color(BG_COLOR); + n64_status.set_font_color(colour); + n64_status.set_wnd_pos(125, Arial_14_GL.height, 100, Arial_14_GL.height); + n64_status.set_font_type(&Arial_14_GL); + n64_status.set_str(fileio_status_text); + n64_status.show_window(); + + tft_dev_draw(true); } void tft_flag_update() { -#if (ENABLE_TFT_DISPLAY >= 1) _tft_update_needed = 1; -#endif } void tft_add_log(char c) { -#if (ENABLE_TFT_DISPLAY >= 1) static int tft_log_line_num = 0; static uint32_t tft_log_pos = 0; static char tft_log[256] = {0}; //Add character to tft log screen tft_log[tft_log_pos] = c; - tft_log_pos++; //Build a new line to display if (c == '\n') @@ -306,6 +294,10 @@ void tft_add_log(char c) tft_log_pos = 0; tft_flag_update(); } + else + { + tft_log_pos++; + } //Exceeded max lines, remove oldest line and shift lines up by one if (tft_log_line_num >= _tft_log_max_lines) @@ -318,5 +310,4 @@ void tft_add_log(char c) _tft_log_text_lines[_tft_log_max_lines - 1] = NULL; tft_log_line_num--; } -#endif } \ No newline at end of file diff --git a/src/tft/tft.h b/src/tft/tft.h index 7babe153..e9208b07 100644 --- a/src/tft/tft.h +++ b/src/tft/tft.h @@ -4,12 +4,7 @@ #ifndef _TFT_H #define _TFT_H -#include -#include "ILI9341_t3n.h" - -#define CENTER ILI9341_t3n::CENTER -#define BG_COLOUR 0x10A2 - +//TFT API void tft_init(); uint8_t tft_change_page(uint8_t page); void tft_force_update(); //Will block until previous DMA complete. @@ -17,4 +12,10 @@ void tft_try_update(); //Will return if DMA busy, or framebuffer hasnt changed void tft_flag_update(); //Mark the framebuffer as dirty, draw at next update call void tft_add_log(char c); +//TFT device specific functions. +void tft_dev_init(); +void tft_dev_draw(bool force); +void *tft_dev_get_fb(); +bool tft_dev_is_busy(); + #endif \ No newline at end of file diff --git a/src/usb64_conf.h b/src/usb64_conf.h index 593c4dba..043a0369 100644 --- a/src/usb64_conf.h +++ b/src/usb64_conf.h @@ -82,6 +82,8 @@ #define TFT_SCK 27 #define TFT_MISO 39 #define TFT_RST 255 +#define TFT_WIDTH 320 +#define TFT_HEIGHT 240 /* DEBUG PRINTERS */ From 5aacff953aabc317fa91191f06905dfd010fa7ea Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 24 Nov 2021 19:17:28 +1030 Subject: [PATCH 007/121] FileIO: Add status check function --- src/fileio.cpp | 8 ++++++++ src/fileio.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/fileio.cpp b/src/fileio.cpp index d593a49e..866370cc 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -8,6 +8,8 @@ #include "fileio.h" #include "memory.h" +static bool fileio_ok = false; + void fileio_init() { if (!fileio_dev_init()) @@ -17,6 +19,7 @@ void fileio_init() else { debug_print_fatfs("[FILEIO] Opened SD card OK!\n"); + fileio_ok = true; } } @@ -115,3 +118,8 @@ void fileio_read_from_file(char *filename, uint32_t file_offset, uint8_t *data, debug_print_status("[FILEIO] Reading %s for %lu bytes ok!\n", filename, len); } } + +bool fileio_detected() +{ + return fileio_ok; +} \ No newline at end of file diff --git a/src/fileio.h b/src/fileio.h index 5f33ca37..8ca54723 100644 --- a/src/fileio.h +++ b/src/fileio.h @@ -6,11 +6,14 @@ #include "usb64_conf.h" +//File access API void fileio_init(void); void fileio_write_to_file(char *filename, uint8_t *data, uint32_t len); void fileio_read_from_file(char *filename, uint32_t file_offset, uint8_t *data, uint32_t len); uint32_t fileio_list_directory(char **list, uint32_t max); +bool fileio_detected(); +//Device specific API. Implement for porting. bool fileio_dev_init(); int fileio_dev_open_dir(const char* dir); void fileio_dev_close_dir(int handle); From d5328e4c0394f8c3efe01ced582bba7f1286a544 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 24 Nov 2021 19:18:06 +1030 Subject: [PATCH 008/121] HAL: Update GPIO read wrapper --- src/n64/n64_controller.c | 2 +- src/n64_wrapper.h | 2 +- src/teensy41/hal_t4.cpp | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/n64/n64_controller.c b/src/n64/n64_controller.c index 7bf64c23..bf1b5112 100644 --- a/src/n64/n64_controller.c +++ b/src/n64/n64_controller.c @@ -183,7 +183,7 @@ void n64_controller_hande_new_edge(n64_input_dev_t *cont) while (n64hal_hs_tick_get() < sample_clock); //Read bit - cont->data_buffer[cont->current_byte] |= n64hal_input_read(cont) << cont->current_bit; + cont->data_buffer[cont->current_byte] |= n64hal_input_read(cont->gpio_pin) << cont->current_bit; cont->current_bit -= 1; //Reset idle timer diff --git a/src/n64_wrapper.h b/src/n64_wrapper.h index fbf9362b..ec62c6f2 100644 --- a/src/n64_wrapper.h +++ b/src/n64_wrapper.h @@ -42,7 +42,7 @@ void n64hal_write_extram(void *tx_buff, void *dst, uint32_t offset, uint32_t len //GPIO wrappers void n64hal_output_set(uint8_t pin, uint8_t level); void n64hal_input_swap(n64_input_dev_t *controller, uint8_t val); -uint8_t n64hal_input_read(n64_input_dev_t *controller); +uint8_t n64hal_input_read(int pin); void n64hal_pin_set_mode(int pin, uint8_t mode); //FileIO wrappers diff --git a/src/teensy41/hal_t4.cpp b/src/teensy41/hal_t4.cpp index 84cd9674..ae01e38a 100644 --- a/src/teensy41/hal_t4.cpp +++ b/src/teensy41/hal_t4.cpp @@ -121,16 +121,16 @@ void n64hal_input_swap(n64_input_dev_t *controller, uint8_t val) } /* - * Function: Returns the data line level for the n64 controller passed to this function. + * Function: Returns the data line level for the pin passed to this function. * Speed critical! * ---------------------------- * Returns: 1 of the line if high, or 0 if the line is low. * - * controller: Pointer to the n64 controller struct which contains the gpio mapping + * Pin number: (See usb64_conf.h) */ -uint8_t n64hal_input_read(n64_input_dev_t *controller) +uint8_t n64hal_input_read(int pin) { - return digitalReadFast(controller->gpio_pin); + return digitalReadFast(pin); } /* From e76849df2618d5eba514cf3053ecf922fe17e97d Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 24 Nov 2021 19:19:23 +1030 Subject: [PATCH 009/121] AStick: Remove Arduino header --- src/analog_stick.cpp | 2 +- src/analog_stick.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/analog_stick.cpp b/src/analog_stick.cpp index 1cbef81b..39b1ef3b 100644 --- a/src/analog_stick.cpp +++ b/src/analog_stick.cpp @@ -1,7 +1,7 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include +#include #include "usb64_conf.h" #include "printf.h" diff --git a/src/analog_stick.h b/src/analog_stick.h index bd578c75..33339d0e 100644 --- a/src/analog_stick.h +++ b/src/analog_stick.h @@ -4,8 +4,6 @@ #ifndef _ANALOG_STICK_H #define _ANALOG_STICK_H -#include - void astick_apply_deadzone(float *out_x, float *out_y, float x, float y, float dz_low, float dz_high); float astick_apply_sensitivity(int sensitivity, float *x, float *y); void astick_apply_snap(float range, float *x, float *y); From f6533f19cfd73d201f6f7bd9f78c187867508056 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 24 Nov 2021 19:23:59 +1030 Subject: [PATCH 010/121] HAL: Add global interrupt functions --- src/n64_wrapper.h | 2 ++ src/teensy41/hal_t4.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/n64_wrapper.h b/src/n64_wrapper.h index ec62c6f2..45b05bff 100644 --- a/src/n64_wrapper.h +++ b/src/n64_wrapper.h @@ -25,6 +25,8 @@ void n64hal_debug_init(); void n64hal_debug_write(char c); void n64hal_attach_interrupt(uint8_t pin, void (*handler)(void), int mode); void n64hal_detach_interrupt(uint8_t pin); +void n64hal_disable_interrupts(); +void n64hal_enable_interrupts(); //RTC wrapper prototypes (For gameboy roms with RTC, i.e Pokemon games) void n64hal_rtc_read(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s); diff --git a/src/teensy41/hal_t4.cpp b/src/teensy41/hal_t4.cpp index ae01e38a..46437575 100644 --- a/src/teensy41/hal_t4.cpp +++ b/src/teensy41/hal_t4.cpp @@ -24,6 +24,16 @@ void n64hal_debug_write(char c) serial_port.write(c); } +void n64hal_disable_interrupts() +{ + noInterrupts(); +} + +void n64hal_enable_interrupts() +{ + interrupts(); +} + /* * Function: Reads a hardware realtime clock and populates day,h,m,s. * Used by Pokemon Gameboy games only with TPAK that have a RTC. From e54699799521461518285c36f6f5e1ca78f9d6e0 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 24 Nov 2021 19:24:30 +1030 Subject: [PATCH 011/121] Memory: Remove remaining Arduino specific code --- src/memory.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/memory.cpp b/src/memory.cpp index 701121fd..36af5007 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -11,8 +11,10 @@ * and automatically flushes for you atleast. You can also manual flush with a button combo. */ -#include +#include +#include #include "memory.h" +#include "n64_wrapper.h" #include "usb64_conf.h" #include "fileio.h" #include "printf.h" @@ -115,7 +117,7 @@ void memory_free_item(void *ptr) //Flush SRAM to flash memory if required void memory_flush_all() { - noInterrupts(); + n64hal_disable_interrupts(); for (unsigned int i = 0; i < sizeof(sram) / sizeof(sram[0]); i++) { if (sram[i].len == 0 || sram[i].data == NULL || sram[i].read_only != 0 || sram[i].dirty == 0) @@ -125,7 +127,7 @@ void memory_flush_all() fileio_write_to_file(sram[i].name, sram[i].data, sram[i].len); sram[i].dirty = 0; } - interrupts(); + n64hal_enable_interrupts(); } void memory_mark_dirty(void *ptr) From 94225b58172d10c70131d1f69ad16df5ca3c790c Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 24 Nov 2021 19:30:43 +1030 Subject: [PATCH 012/121] N64: Remove Arduino headers --- src/n64/n64_controller.c | 2 -- src/n64/n64_mempak.c | 2 +- src/n64/n64_settings.c | 3 +-- src/n64/n64_transferpak_gbcarts.c | 3 +-- src/n64/n64_virtualpak.c | 2 -- src/usb64_conf.h | 9 +++++++-- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/n64/n64_controller.c b/src/n64/n64_controller.c index bf1b5112..9f690e6d 100644 --- a/src/n64/n64_controller.c +++ b/src/n64/n64_controller.c @@ -1,8 +1,6 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include -#include "printf.h" #include "usb64_conf.h" #include "n64_mempak.h" #include "n64_virtualpak.h" diff --git a/src/n64/n64_mempak.c b/src/n64/n64_mempak.c index 7f9fcd56..51213a2c 100644 --- a/src/n64/n64_mempak.c +++ b/src/n64/n64_mempak.c @@ -1,7 +1,7 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include +#include "usb64_conf.h" #include "n64_mempak.h" #include "n64_virtualpak.h" #include "n64_settings.h" diff --git a/src/n64/n64_settings.c b/src/n64/n64_settings.c index 050ae90c..1fa40804 100644 --- a/src/n64/n64_settings.c +++ b/src/n64/n64_settings.c @@ -1,10 +1,9 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include +#include "usb64_conf.h" #include "n64_settings.h" #include "n64_wrapper.h" -#include "printf.h" n64_settings *_settings = NULL; diff --git a/src/n64/n64_transferpak_gbcarts.c b/src/n64/n64_transferpak_gbcarts.c index 0e80a0db..e9f2a056 100644 --- a/src/n64/n64_transferpak_gbcarts.c +++ b/src/n64/n64_transferpak_gbcarts.c @@ -7,8 +7,7 @@ * Tranferpak emulation is my own RE. */ -#include -#include "printf.h" +#include "usb64_conf.h" #include "n64_mempak.h" #include "n64_virtualpak.h" #include "n64_settings.h" diff --git a/src/n64/n64_virtualpak.c b/src/n64/n64_virtualpak.c index 063d0ff5..30b340e2 100644 --- a/src/n64/n64_virtualpak.c +++ b/src/n64/n64_virtualpak.c @@ -1,8 +1,6 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include -#include "printf.h" #include "usb64_conf.h" #include "n64_mempak.h" #include "n64_virtualpak.h" diff --git a/src/usb64_conf.h b/src/usb64_conf.h index 043a0369..93e61059 100644 --- a/src/usb64_conf.h +++ b/src/usb64_conf.h @@ -1,12 +1,18 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT +#include +#include +#include +#include +#include "printf.h" + #ifndef _USB64_CONF_h #define _USB64_CONF_h /* DEBUGGING OUTPUT - WARNING SOME OF THESE MAY BREAK TIMING AND CAUSE ISSUES USE ONLY FOR DEBUGGING */ -#define serial_port Serial +#define serial_port Serial1 #define DEBUG_STATUS 1 //General information #define DEBUG_N64 0 //For debugging N64 low level info #define DEBUG_TPAK 0 //For debugging N64 TPAK low level info. It's complex so has its own flag @@ -87,7 +93,6 @@ /* DEBUG PRINTERS */ -#include "printf.h" #define debug_print_status(fmt, ...) do { if (DEBUG_STATUS) printf(fmt, ##__VA_ARGS__); } while (0) #define debug_print_n64(fmt, ...) do { if (DEBUG_N64) printf(fmt, ##__VA_ARGS__); } while (0) #define debug_print_tpak(fmt, ...) do { if (DEBUG_TPAK) printf(fmt, ##__VA_ARGS__); } while (0) From a9cf44bc053c33d3023be5f9cd7bf70d225cd4b5 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 24 Nov 2021 19:36:26 +1030 Subject: [PATCH 013/121] usb64: Clean up includes --- src/analog_stick.cpp | 2 -- src/analog_stick.h | 2 ++ src/fileio.cpp | 3 --- src/main.cpp | 3 +-- src/memory.cpp | 4 +--- src/tft/controller_icon.h | 2 -- src/tft/tft.cpp | 1 - src/tft/usb64_logo.h | 2 -- src/usb64_conf.h | 8 ++++++++ 9 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/analog_stick.cpp b/src/analog_stick.cpp index 39b1ef3b..0d7e8453 100644 --- a/src/analog_stick.cpp +++ b/src/analog_stick.cpp @@ -1,9 +1,7 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include #include "usb64_conf.h" -#include "printf.h" void astick_apply_deadzone(float *out_x, float *out_y, float x, float y, float dz_low, float dz_high) { float magnitude = sqrtf(powf(x,2) + powf(y,2)); diff --git a/src/analog_stick.h b/src/analog_stick.h index 33339d0e..8ba00b4d 100644 --- a/src/analog_stick.h +++ b/src/analog_stick.h @@ -4,6 +4,8 @@ #ifndef _ANALOG_STICK_H #define _ANALOG_STICK_H +#include "usb64_conf.h" + void astick_apply_deadzone(float *out_x, float *out_y, float x, float y, float dz_low, float dz_high); float astick_apply_sensitivity(int sensitivity, float *x, float *y); void astick_apply_snap(float range, float *x, float *y); diff --git a/src/fileio.cpp b/src/fileio.cpp index 866370cc..ee6f53b2 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -1,10 +1,7 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include -#include #include "usb64_conf.h" -#include "printf.h" #include "fileio.h" #include "memory.h" diff --git a/src/main.cpp b/src/main.cpp index 674ad557..942c9ec4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,8 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include "input.h" -#include "printf.h" #include "usb64_conf.h" +#include "input.h" #include "n64_controller.h" #include "n64_transferpak_gbcarts.h" #include "n64_virtualpak.h" diff --git a/src/memory.cpp b/src/memory.cpp index 36af5007..5d67d7f2 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -11,13 +11,11 @@ * and automatically flushes for you atleast. You can also manual flush with a button combo. */ -#include -#include +#include "usb64_conf.h" #include "memory.h" #include "n64_wrapper.h" #include "usb64_conf.h" #include "fileio.h" -#include "printf.h" static sram_storage sram[32] = {0}; diff --git a/src/tft/controller_icon.h b/src/tft/controller_icon.h index 34762892..125f9a3b 100644 --- a/src/tft/controller_icon.h +++ b/src/tft/controller_icon.h @@ -4,8 +4,6 @@ // Image Size : 48x45 pixels // Memory usage : 4320 bytes -#include - const unsigned short controller_icon[2160] PROGMEM = { 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, // 0x0010 (16) pixels 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, // 0x0020 (32) pixels diff --git a/src/tft/tft.cpp b/src/tft/tft.cpp index c9bd47ac..91ab673c 100644 --- a/src/tft/tft.cpp +++ b/src/tft/tft.cpp @@ -1,7 +1,6 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include #include "usb64_conf.h" #include "n64_wrapper.h" #include "n64_controller.h" diff --git a/src/tft/usb64_logo.h b/src/tft/usb64_logo.h index 982c6ae4..3d016c60 100644 --- a/src/tft/usb64_logo.h +++ b/src/tft/usb64_logo.h @@ -4,8 +4,6 @@ // Image Size : 120x35 pixels // Memory usage : 8400 bytes -#include - const unsigned short usb64_logo[4200] PROGMEM = { 0x10A2, 0x10A2, 0x0020, 0x8C51, 0x8C71, 0x528A, 0x5ACB, 0x5ACB, 0x5ACB, 0x5ACB, 0x5ACB, 0x528A, 0x8C51, 0x10A2, 0x632C, 0xAD55, // 0x0010 (16) pixels 0x4A69, 0x5ACB, 0x5ACB, 0x5ACB, 0x5ACB, 0x5ACB, 0x52AA, 0x5AEB, 0x5ACB, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, 0x10A2, // 0x0020 (32) pixels diff --git a/src/usb64_conf.h b/src/usb64_conf.h index 93e61059..9980996e 100644 --- a/src/usb64_conf.h +++ b/src/usb64_conf.h @@ -1,10 +1,14 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT +#ifdef ARDUINO +#include +#endif #include #include #include #include +#include #include "printf.h" #ifndef _USB64_CONF_h @@ -91,6 +95,10 @@ #define TFT_WIDTH 320 #define TFT_HEIGHT 240 +/* Define for variables to store in flash only */ +#ifndef PROGMEM +#define PROGMEM +#endif /* DEBUG PRINTERS */ #define debug_print_status(fmt, ...) do { if (DEBUG_STATUS) printf(fmt, ##__VA_ARGS__); } while (0) From fa945b410a2563aa317b38b3dd51d9675a08b9df Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 24 Nov 2021 19:39:15 +1030 Subject: [PATCH 014/121] TFT: Move TFT code to src folder --- src/{tft => }/tft.cpp | 0 src/{tft => }/tft.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/{tft => }/tft.cpp (100%) rename src/{tft => }/tft.h (100%) diff --git a/src/tft/tft.cpp b/src/tft.cpp similarity index 100% rename from src/tft/tft.cpp rename to src/tft.cpp diff --git a/src/tft/tft.h b/src/tft.h similarity index 100% rename from src/tft/tft.h rename to src/tft.h From b1032b3f5eaa3e40c1832caee67c22a3a035f095 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 24 Nov 2021 19:43:28 +1030 Subject: [PATCH 015/121] usb64: Refactor folders --- .gitmodules | 6 +++--- platformio.ini | 22 ++++++++++------------ src/{ => lib}/printf | 0 src/{ => teensy41}/ILI9341_t3n | 0 src/{ => teensy41}/USBHost_t36 | 0 5 files changed, 13 insertions(+), 15 deletions(-) rename src/{ => lib}/printf (100%) rename src/{ => teensy41}/ILI9341_t3n (100%) rename src/{ => teensy41}/USBHost_t36 (100%) diff --git a/.gitmodules b/.gitmodules index 510011ce..cdce86f0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,11 +1,11 @@ [submodule "src/printf"] - path = src/printf + path = src/lib/printf url = https://github.com/mpaland/printf [submodule "src/USBHost_t36"] - path = src/USBHost_t36 + path = src/teensy41/USBHost_t36 url = https://github.com/Ryzee119/USBHost_t36.git [submodule "src/ILI9341_t3n"] - path = src/ILI9341_t3n + path = src/teensy41/ILI9341_t3n url = https://github.com/KurtE/ILI9341_t3n.git diff --git a/platformio.ini b/platformio.ini index 7d7fbaf0..3cbb1fc8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -25,17 +25,17 @@ src_filter = +<*.cpp> +<*.c> + - + - + + + + + build_flags = -O2 -Wall - -Isrc/ + -Isrc -Isrc/n64 - -Isrc/printf - -Isrc/tinyalloc + -Isrc/tft -Isrc/lib + -Isrc/lib/printf ; Printf Configuration -DPRINTF_DISABLE_SUPPORT_FLOAT @@ -58,17 +58,15 @@ lib_ignore = USBHost_t36 src_filter = ${common_env_data.src_filter} - + - + - + + + + + + + + + - + build_flags = ${common_env_data.build_flags} - -Isrc/USBHost_t36 - -Isrc/ILI9341_t3n/src - -Isrc/tft + -Isrc/teensy41/USBHost_t36 + -Isrc/teensy41/ILI9341_t3n/src ; -DUSBHOST_PRINT_DEBUG ; -DDEBUG_JOYSTICK diff --git a/src/printf b/src/lib/printf similarity index 100% rename from src/printf rename to src/lib/printf diff --git a/src/ILI9341_t3n b/src/teensy41/ILI9341_t3n similarity index 100% rename from src/ILI9341_t3n rename to src/teensy41/ILI9341_t3n diff --git a/src/USBHost_t36 b/src/teensy41/USBHost_t36 similarity index 100% rename from src/USBHost_t36 rename to src/teensy41/USBHost_t36 From 5ff0b3c8f40129a29d7901481d83de458df6aadc Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Mon, 29 Nov 2021 20:28:30 +1030 Subject: [PATCH 016/121] USBH: Replace USB Stack with TinyUSB --- .gitmodules | 9 ++++----- src/lib/tinyusb | 1 + src/teensy41/ILI9341_t3n | 2 +- src/teensy41/USBHost_t36 | 1 - 4 files changed, 6 insertions(+), 7 deletions(-) create mode 160000 src/lib/tinyusb delete mode 160000 src/teensy41/USBHost_t36 diff --git a/.gitmodules b/.gitmodules index cdce86f0..849b0eff 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,10 +2,9 @@ path = src/lib/printf url = https://github.com/mpaland/printf -[submodule "src/USBHost_t36"] - path = src/teensy41/USBHost_t36 - url = https://github.com/Ryzee119/USBHost_t36.git - -[submodule "src/ILI9341_t3n"] +[submodule "src/lib/tinyusb"] + path = src/lib/tinyusb + url = https://github.com/hathach/tinyusb.git +[submodule "src/teensy41/ILI9341_t3n"] path = src/teensy41/ILI9341_t3n url = https://github.com/KurtE/ILI9341_t3n.git diff --git a/src/lib/tinyusb b/src/lib/tinyusb new file mode 160000 index 00000000..ae73873b --- /dev/null +++ b/src/lib/tinyusb @@ -0,0 +1 @@ +Subproject commit ae73873b5cba0eb11c89165f4559964940430d44 diff --git a/src/teensy41/ILI9341_t3n b/src/teensy41/ILI9341_t3n index bb307299..b8844f3e 160000 --- a/src/teensy41/ILI9341_t3n +++ b/src/teensy41/ILI9341_t3n @@ -1 +1 @@ -Subproject commit bb30729973d1d9f14648fb20543a777ee9b91f20 +Subproject commit b8844f3e4a6c40436bb88f61dfcc89c36f5bef6f diff --git a/src/teensy41/USBHost_t36 b/src/teensy41/USBHost_t36 deleted file mode 160000 index 637c4cbe..00000000 --- a/src/teensy41/USBHost_t36 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 637c4cbe7266795dea6490a4de0f38d8ec289643 From 2899542bd88dc7bf9956287a798e39a2cfec3949 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 12:22:45 +1030 Subject: [PATCH 017/121] TinyUSB: Update submodule --- src/lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tinyusb b/src/lib/tinyusb index ae73873b..7a019582 160000 --- a/src/lib/tinyusb +++ b/src/lib/tinyusb @@ -1 +1 @@ -Subproject commit ae73873b5cba0eb11c89165f4559964940430d44 +Subproject commit 7a0195828aee4cce473fc84cb0ba132c9f0bd64d From 3e6a1e179fc29b3fd4cbb1890fa4ca07e3f57020 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 12:24:52 +1030 Subject: [PATCH 018/121] USBH: Add Teensy4 TinyUSB driver --- platformio.ini | 34 +++++++++----- src/lib/tusb_config.h | 96 ++++++++++++++++++++++++++++++++++++++++ src/teensy41/usbh_t4.cpp | 72 ++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+), 12 deletions(-) create mode 100644 src/lib/tusb_config.h create mode 100644 src/teensy41/usbh_t4.cpp diff --git a/platformio.ini b/platformio.ini index 3cbb1fc8..3f51430a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -28,6 +28,11 @@ src_filter = + + + + + + + + + + + build_flags = -O2 -Wall @@ -36,6 +41,9 @@ build_flags = -Isrc/tft -Isrc/lib -Isrc/lib/printf + -Isrc/lib/tinyusb/src + -DCFG_TUSB_DEBUG_PRINTF="tusb_printf_hook" + -DCFG_TUSB_DEBUG=2 ; Printf Configuration -DPRINTF_DISABLE_SUPPORT_FLOAT @@ -43,30 +51,32 @@ build_flags = -DPRINTF_DISABLE_SUPPORT_LONG_LONG -DPRINTF_DISABLE_SUPPORT_PTRDIFF_T - ; Tinyalloc Configuration - -DTA_DISABLE_COMPACT - [env:teensy41] platform = teensy@~4.13.1 board = teensy41 framework = arduino -monitor_port = COM25 -monitor_speed = 256000 - -; Disable the inbuilt framework lib so I can use my own fork -lib_ignore = USBHost_t36 src_filter = ${common_env_data.src_filter} - + + + + + + ;TinyUSB (T4 specific) + + + + + + + + build_flags = ${common_env_data.build_flags} - -Isrc/teensy41/USBHost_t36 + -Isrc/teensy41/ -Isrc/teensy41/ILI9341_t3n/src - ; -DUSBHOST_PRINT_DEBUG - ; -DDEBUG_JOYSTICK + ;TinyUSB (T4 specific) + -Isrc/lib/tinyusb/hw/mcu/nxp/mcux-sdk/CMSIS/Include + -Isrc/lib/tinyusb/hw/mcu/nxp/mcux-sdk/devices/MIMXRT1062 + -Isrc/lib/tinyusb/hw/mcu/nxp/mcux-sdk/devices/MIMXRT1062/drivers + -Isrc/lib/tinyusb/hw/mcu/nxp/mcux-sdk/drivers/common + -DCPU_MIMXRT1062DVL6A + -DCFG_TUSB_MCU=OPT_MCU_MIMXRT10XX + -DMCU_VARIANT=MIMXRT1062 diff --git a/src/lib/tusb_config.h b/src/lib/tusb_config.h new file mode 100644 index 00000000..ea65d7ae --- /dev/null +++ b/src/lib/tusb_config.h @@ -0,0 +1,96 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +// defined by compiler flags for flexibility +#ifndef CFG_TUSB_MCU + #error CFG_TUSB_MCU must be defined +#endif + +#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX + #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST | OPT_MODE_FULL_SPEED) +#else + #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST | OPT_MODE_FULL_SPEED) +#endif + +#ifndef CFG_TUSB_OS +#define CFG_TUSB_OS OPT_OS_NONE +#endif + +// CFG_TUSB_DEBUG is defined by compiler in DEBUG build +// #define CFG_TUSB_DEBUG 0 + +/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. + * Tinyusb use follows macros to declare transferring memory so that they can be put + * into those specific section. + * e.g + * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) + * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) + */ +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(32))) +#endif + +//-------------------------------------------------------------------- +// CONFIGURATION +//-------------------------------------------------------------------- + +// Size of buffer to hold descriptors and other data used for enumeration +#define CFG_TUH_ENUMERATION_BUFSIZE 256 + +#define CFG_TUH_HUB 1 +#define CFG_TUH_CDC 0 +#define CFG_TUH_HID 0 // typical keyboard + mouse device can have 3-4 HID interfaces +#define CFG_TUH_MSC 0 +#define CFG_TUH_VENDOR 0 +#define CFG_TUH_XINPUT 4 + +// max device support (excluding hub device) +// 1 hub typically has 4 ports +#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) + +//------------- HID -------------// + +#define CFG_TUH_HID_EP_BUFSIZE 64 + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/src/teensy41/usbh_t4.cpp b/src/teensy41/usbh_t4.cpp new file mode 100644 index 00000000..8a288609 --- /dev/null +++ b/src/teensy41/usbh_t4.cpp @@ -0,0 +1,72 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include "tusb.h" +#include "printf.h" + +void USB_OTG2_IRQHandler(void) +{ + tuh_int_handler(1); +} + +void usbh_dev_init() +{ + // Teensy 4.0 PLL & USB PHY powerup + while (1) + { + uint32_t n = CCM_ANALOG_PLL_USB2; + if (n & CCM_ANALOG_PLL_USB2_DIV_SELECT) + { + CCM_ANALOG_PLL_USB2_CLR = 0xC000; // get out of 528 MHz mode + CCM_ANALOG_PLL_USB2_SET = CCM_ANALOG_PLL_USB2_BYPASS; + CCM_ANALOG_PLL_USB2_CLR = CCM_ANALOG_PLL_USB2_POWER | + CCM_ANALOG_PLL_USB2_DIV_SELECT | + CCM_ANALOG_PLL_USB2_ENABLE | + CCM_ANALOG_PLL_USB2_EN_USB_CLKS; + continue; + } + if (!(n & CCM_ANALOG_PLL_USB2_ENABLE)) + { + CCM_ANALOG_PLL_USB2_SET = CCM_ANALOG_PLL_USB2_ENABLE; // enable + continue; + } + if (!(n & CCM_ANALOG_PLL_USB2_POWER)) + { + CCM_ANALOG_PLL_USB2_SET = CCM_ANALOG_PLL_USB2_POWER; // power up + continue; + } + if (!(n & CCM_ANALOG_PLL_USB2_LOCK)) + { + continue; // wait for lock + } + if (n & CCM_ANALOG_PLL_USB2_BYPASS) + { + CCM_ANALOG_PLL_USB2_CLR = CCM_ANALOG_PLL_USB2_BYPASS; // turn off bypass + continue; + } + if (!(n & CCM_ANALOG_PLL_USB2_EN_USB_CLKS)) + { + CCM_ANALOG_PLL_USB2_SET = CCM_ANALOG_PLL_USB2_EN_USB_CLKS; // enable + continue; + } + break; // USB2 PLL up and running + } + // turn on USB clocks (should already be on) + CCM_CCGR6 |= CCM_CCGR6_USBOH3(CCM_CCGR_ON); + // turn on USB2 PHY + USBPHY2_CTRL_CLR = USBPHY_CTRL_SFTRST | USBPHY_CTRL_CLKGATE; + USBPHY2_CTRL_SET = USBPHY_CTRL_ENUTMILEVEL2 | USBPHY_CTRL_ENUTMILEVEL3; + USBPHY2_PWD = 0; + +#ifdef ARDUINO_TEENSY41 + IOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_40 = 5; + IOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_40 = 0x0008; // slow speed, weak 150 ohm drive + GPIO8_GDIR |= 1 << 26; + GPIO8_DR_SET = 1 << 26; +#endif + + delay(10); + NVIC_DISABLE_IRQ(IRQ_USB2); + attachInterruptVector(IRQ_USB2, USB_OTG2_IRQHandler); +} From a8709a840310410c0f5f0099a744f9cb523173cd Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 12:25:14 +1030 Subject: [PATCH 019/121] USBH: Add xinput driver --- src/lib/xinput_host.c | 427 ++++++++++++++++++++++++++++++++++++++++++ src/lib/xinput_host.h | 149 +++++++++++++++ 2 files changed, 576 insertions(+) create mode 100644 src/lib/xinput_host.c create mode 100644 src/lib/xinput_host.h diff --git a/src/lib/xinput_host.c b/src/lib/xinput_host.c new file mode 100644 index 00000000..35b372b4 --- /dev/null +++ b/src/lib/xinput_host.c @@ -0,0 +1,427 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include "tusb_option.h" + +#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_XINPUT) + +#include "host/usbh.h" +#include "host/usbh_classdriver.h" +#include "xinput_host.h" + +typedef struct +{ + uint8_t inst_count; + xinputh_interface_t instances[CFG_TUH_XINPUT]; +} xinputh_device_t; + +static xinputh_device_t _xinputh_dev[CFG_TUH_DEVICE_MAX]; + +TU_ATTR_ALWAYS_INLINE static inline xinputh_device_t *get_dev(uint8_t dev_addr) +{ + return &_xinputh_dev[dev_addr - 1]; +} + +TU_ATTR_ALWAYS_INLINE static inline xinputh_interface_t *get_instance(uint8_t dev_addr, uint8_t instance) +{ + return &_xinputh_dev[dev_addr - 1].instances[instance]; +} + +static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr) +{ + for (uint8_t inst = 0; inst < CFG_TUH_XINPUT; inst++) + { + xinputh_interface_t *hid = get_instance(dev_addr, inst); + + if ((ep_addr == hid->ep_in) || (ep_addr == hid->ep_out)) + return inst; + } + + return 0xff; +} + +static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf) +{ + for (uint8_t inst = 0; inst < CFG_TUH_XINPUT; inst++) + { + xinputh_interface_t *hid = get_instance(dev_addr, inst); + + if ((hid->itf_num == itf) && (hid->ep_in || hid->ep_out)) + return inst; + } + + return 0xff; +} + +static void wait_for_tx_complete(uint8_t dev_addr, uint8_t ep_out) +{ + while (usbh_edpt_busy(dev_addr, ep_out)) + tuh_task(); +} + +bool tuh_xinput_receive_report(uint8_t dev_addr, uint8_t instance) +{ + xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); + TU_VERIFY(usbh_edpt_claim(dev_addr, xid_itf->ep_in)); + return usbh_edpt_xfer(dev_addr, xid_itf->ep_in, xid_itf->epin_buf, xid_itf->epin_size); +} + +bool tuh_xinput_send_report(uint8_t dev_addr, uint8_t instance, const uint8_t *txbuf, uint16_t len) +{ + xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); + + TU_ASSERT(len <= xid_itf->epout_size); + TU_VERIFY(usbh_edpt_claim(dev_addr, xid_itf->ep_out)); + + memcpy(xid_itf->epout_buf, txbuf, len); + return usbh_edpt_xfer(dev_addr, xid_itf->ep_out, xid_itf->epout_buf, len); +} + +bool tuh_xinput_set_led(uint8_t dev_addr, uint8_t instance, uint8_t quadrant, bool block) +{ + xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); + uint8_t txbuf[32]; + uint16_t len; + switch (xid_itf->type) + { + case XBOX360_WIRELESS: + memcpy(txbuf, xbox360w_led, sizeof(xbox360w_led)); + txbuf[3] = (quadrant == 0) ? 0x40 : (0x40 | (quadrant + 5)); + len = sizeof(xbox360w_led); + break; + case XBOX360_WIRED: + memcpy(txbuf, xbox360_wired_led, sizeof(xbox360_wired_led)); + txbuf[2] = (quadrant == 0) ? 0 : (quadrant + 5); + len = sizeof(xbox360_wired_led); + break; + default: + return true; + } + bool ret = tuh_xinput_send_report(dev_addr, instance, txbuf, len); + if (block && ret) + { + wait_for_tx_complete(dev_addr, xid_itf->ep_out); + } + return ret; +} + +bool tuh_xinput_set_rumble(uint8_t dev_addr, uint8_t instance, uint8_t lValue, uint8_t rValue, bool block) +{ + xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); + uint8_t txbuf[32]; + uint16_t len; + + switch (xid_itf->type) + { + case XBOX360_WIRELESS: + memcpy(txbuf, xbox360w_rumble, sizeof(xbox360w_rumble)); + txbuf[5] = lValue; + txbuf[6] = rValue; + len = sizeof(xbox360w_led); + break; + case XBOX360_WIRED: + memcpy(txbuf, xbox360_wired_rumble, sizeof(xbox360_wired_rumble)); + txbuf[3] = lValue; + txbuf[4] = rValue; + len = sizeof(xbox360_wired_rumble); + break; + case XBOXONE: + memcpy(txbuf, xboxone_rumble, sizeof(xboxone_rumble)); + txbuf[8] = lValue / 2.6f; //Scale is 0 to 100 + txbuf[9] = rValue / 2.6f; //Scale is 0 to 100 + len = sizeof(xboxone_rumble); + break; + case XBOXOG: + memcpy(txbuf, xboxog_rumble, sizeof(xboxog_rumble)); + txbuf[2] = lValue; + txbuf[3] = lValue; + txbuf[4] = rValue; + txbuf[5] = rValue; + len = sizeof(xboxog_rumble); + break; + default: + return true; + } + bool ret = tuh_xinput_send_report(dev_addr, instance, txbuf, len); + if (block && ret) + { + wait_for_tx_complete(dev_addr, xid_itf->ep_out); + } + return true; +} + +//--------------------------------------------------------------------+ +// USBH API +//--------------------------------------------------------------------+ +void xinputh_init(void) +{ + tu_memclr(_xinputh_dev, sizeof(_xinputh_dev)); +} + +bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) +{ + TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX); + + xinput_type_t type = XINPUT_UNKNOWN; + if (desc_itf->bNumEndpoints < 2) + type = XINPUT_UNKNOWN; + else if (desc_itf->bInterfaceSubClass == 0x5D && //Xbox360 wireless bInterfaceSubClass + desc_itf->bInterfaceProtocol == 0x81) //Xbox360 wireless bInterfaceProtocol + type = XBOX360_WIRELESS; + else if (desc_itf->bInterfaceSubClass == 0x5D && //Xbox360 wired bInterfaceSubClass + desc_itf->bInterfaceProtocol == 0x01) //Xbox360 wired bInterfaceProtocol + type = XBOX360_WIRED; + else if (desc_itf->bInterfaceSubClass == 0x47 && //Xbone and SX bInterfaceSubClass + desc_itf->bInterfaceProtocol == 0xD0) //Xbone and SX bInterfaceProtocol + type = XBOXONE; + else if (desc_itf->bInterfaceClass == 0x58 && //XboxOG bInterfaceClass + desc_itf->bInterfaceSubClass == 0x42) //XboxOG bInterfaceSubClass + type = XBOXOG; + + if (type == XINPUT_UNKNOWN) + { + TU_LOG2("XINPUT: Not a valid interface\n"); + return false; + } + + TU_LOG2("XINPUT opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); + + xinputh_device_t *xinput_dev = get_dev(dev_addr); + TU_ASSERT(xinput_dev->inst_count < CFG_TUH_XINPUT, 0); + + xinputh_interface_t *xid_itf = get_instance(dev_addr, xinput_dev->inst_count); + xid_itf->itf_num = desc_itf->bInterfaceNumber; + xid_itf->type = type; + + //Parse descriptor for all endpoints and open them + uint8_t const *p_desc = (uint8_t const *)desc_itf; + int endpoint = 0; + int pos = 0; + while (endpoint < desc_itf->bNumEndpoints && pos < max_len) + { + if (tu_desc_type(p_desc) != TUSB_DESC_ENDPOINT) + { + pos += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + continue; + } + tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *)p_desc; + TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); + TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep)); + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT) + { + xid_itf->ep_out = desc_ep->bEndpointAddress; + xid_itf->epout_size = tu_edpt_packet_size(desc_ep); + } + else + { + xid_itf->ep_in = desc_ep->bEndpointAddress; + xid_itf->epin_size = tu_edpt_packet_size(desc_ep); + } + endpoint++; + pos += tu_desc_len(p_desc); + p_desc = tu_desc_next(p_desc); + } + + xinput_dev->inst_count++; + return true; +} + +bool xinputh_set_config(uint8_t dev_addr, uint8_t itf_num) +{ + uint8_t instance = get_instance_id_by_itfnum(dev_addr, itf_num); + xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); + + if (xid_itf->type == XBOX360_WIRELESS) + { + tuh_xinput_send_report(dev_addr, instance, xbox360w_controller_info, sizeof(xbox360w_controller_info)); + wait_for_tx_complete(dev_addr, xid_itf->ep_out); + tuh_xinput_send_report(dev_addr, instance, xbox360w_unknown, sizeof(xbox360w_unknown)); + wait_for_tx_complete(dev_addr, xid_itf->ep_out); + tuh_xinput_send_report(dev_addr, instance, xbox360w_rumble_enable, sizeof(xbox360w_rumble_enable)); + wait_for_tx_complete(dev_addr, xid_itf->ep_out); + } + else if (xid_itf->type == XBOX360_WIRED) + { + } + else if (xid_itf->type == XBOXONE) + { + uint16_t PID, VID; + tuh_vid_pid_get(dev_addr, &VID, &PID); + + tuh_xinput_send_report(dev_addr, instance, xboxone_start_input, sizeof(xboxone_start_input)); + wait_for_tx_complete(dev_addr, xid_itf->ep_out); + + //Init packet for XBONE S/Elite controllers (return from bluetooth mode) + if (VID == 0x045e && (PID == 0x02ea || PID == 0x0b00)) + { + tuh_xinput_send_report(dev_addr, instance, xboxone_s_init, sizeof(xboxone_s_init)); + wait_for_tx_complete(dev_addr, xid_itf->ep_out); + } + + //Required for PDP aftermarket controllers + if (VID == 0x0e6f) + { + tuh_xinput_send_report(dev_addr, instance, xboxone_pdp_init1, sizeof(xboxone_pdp_init1)); + wait_for_tx_complete(dev_addr, xid_itf->ep_out); + tuh_xinput_send_report(dev_addr, instance, xboxone_pdp_init2, sizeof(xboxone_pdp_init2)); + wait_for_tx_complete(dev_addr, xid_itf->ep_out); + tuh_xinput_send_report(dev_addr, instance, xboxone_pdp_init3, sizeof(xboxone_pdp_init3)); + wait_for_tx_complete(dev_addr, xid_itf->ep_out); + } + } + + if (tuh_xinput_mount_cb) + { + tuh_xinput_mount_cb(dev_addr, instance, NULL); + } + return true; +} + +bool xinputh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + (void)result; + uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const instance = get_instance_id_by_epaddr(dev_addr, ep_addr); + xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); + xinput_gamepad_t *pad = &xid_itf->pad; + uint8_t *rdata = xid_itf->epin_buf; + + if (dir == TUSB_DIR_IN) + { + TU_LOG2("Get Report callback (%u, %u)\r\n", dev_addr, instance); + TU_LOG2_MEM(xid_itf->epin_buf, xferred_bytes, 2); + if (xid_itf->type == XBOX360_WIRED) + { + #define GET_USHORT(a) (uint16_t)((a)[1] << 8 | (a)[0]) + #define GET_SHORT(a) ((int16_t)GET_USHORT(a)) + if (rdata[1] == 0x14) + { + tu_memclr(pad, sizeof(xinput_gamepad_t)); + uint16_t wButtons = rdata[3] << 8 | rdata[2]; + + //Map digital buttons + if (wButtons & (1 << 0)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_UP; + if (wButtons & (1 << 1)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; + if (wButtons & (1 << 2)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; + if (wButtons & (1 << 3)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; + if (wButtons & (1 << 4)) pad->wButtons |= XINPUT_GAMEPAD_START; + if (wButtons & (1 << 5)) pad->wButtons |= XINPUT_GAMEPAD_BACK; + if (wButtons & (1 << 6)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; + if (wButtons & (1 << 7)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; + if (wButtons & (1 << 8)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; + if (wButtons & (1 << 9)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; + if (wButtons & (1 << 12)) pad->wButtons |= XINPUT_GAMEPAD_A; + if (wButtons & (1 << 13)) pad->wButtons |= XINPUT_GAMEPAD_B; + if (wButtons & (1 << 14)) pad->wButtons |= XINPUT_GAMEPAD_X; + if (wButtons & (1 << 15)) pad->wButtons |= XINPUT_GAMEPAD_Y; + + //Map the left and right triggers + pad->bLeftTrigger = rdata[4]; + pad->bRightTrigger = rdata[5]; + + //Map analog sticks + pad->sThumbLX = rdata[7] << 8 | rdata[6]; + pad->sThumbLY = rdata[9] << 8 | rdata[8]; + pad->sThumbRX = rdata[11] << 8 | rdata[10]; + pad->sThumbRY = rdata[13] << 8 | rdata[12]; + } + } + else if (xid_itf->type == XBOXONE) + { + if (rdata[0] == 0x20) + { + tu_memclr(pad, sizeof(xinput_gamepad_t)); + uint16_t wButtons = rdata[5] << 8 | rdata[4]; + + //Map digital buttons + if (wButtons & (1 << 8)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_UP; + if (wButtons & (1 << 9)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; + if (wButtons & (1 << 10)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; + if (wButtons & (1 << 11)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; + if (wButtons & (1 << 2)) pad->wButtons |= XINPUT_GAMEPAD_START; + if (wButtons & (1 << 3)) pad->wButtons |= XINPUT_GAMEPAD_BACK; + if (wButtons & (1 << 14)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; + if (wButtons & (1 << 15)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; + if (wButtons & (1 << 12)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; + if (wButtons & (1 << 13)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; + if (wButtons & (1 << 4)) pad->wButtons |= XINPUT_GAMEPAD_A; + if (wButtons & (1 << 5)) pad->wButtons |= XINPUT_GAMEPAD_B; + if (wButtons & (1 << 6)) pad->wButtons |= XINPUT_GAMEPAD_X; + if (wButtons & (1 << 7)) pad->wButtons |= XINPUT_GAMEPAD_Y; + + //Map the left and right triggers + pad->bLeftTrigger = (rdata[7] << 8 | rdata[6]) >> 2; + pad->bRightTrigger = (rdata[9] << 8 | rdata[8]) >> 2; + + //Map analog sticks + pad->sThumbLX = rdata[11] << 8 | rdata[10]; + pad->sThumbLY = rdata[13] << 8 | rdata[12]; + pad->sThumbRX = rdata[15] << 8 | rdata[14]; + pad->sThumbRY = rdata[17] << 8 | rdata[16]; + } + } + else if (xid_itf->type == XBOXOG) + { + if (rdata[1] == 0x14) + { + tu_memclr(pad, sizeof(xinput_gamepad_t)); + uint16_t wButtons = rdata[3] << 8 | rdata[2]; + + //Map digital buttons + if (wButtons & (1 << 0)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_UP; + if (wButtons & (1 << 1)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; + if (wButtons & (1 << 2)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; + if (wButtons & (1 << 3)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; + if (wButtons & (1 << 4)) pad->wButtons |= XINPUT_GAMEPAD_START; + if (wButtons & (1 << 5)) pad->wButtons |= XINPUT_GAMEPAD_BACK; + if (wButtons & (1 << 6)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; + if (wButtons & (1 << 7)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; + + if (rdata[4] > 0x20) pad->wButtons |= XINPUT_GAMEPAD_A; + if (rdata[5] > 0x20) pad->wButtons |= XINPUT_GAMEPAD_B; + if (rdata[6] > 0x20) pad->wButtons |= XINPUT_GAMEPAD_X; + if (rdata[7] > 0x20) pad->wButtons |= XINPUT_GAMEPAD_Y; + if (rdata[8] > 0x20) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; + if (rdata[9] > 0x20) pad->wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; + + //Map the left and right triggers + pad->bLeftTrigger = rdata[10]; + pad->bRightTrigger = rdata[11]; + + //Map analog sticks + pad->sThumbLX = rdata[13] << 8 | rdata[12]; + pad->sThumbLY = rdata[15] << 8 | rdata[14]; + pad->sThumbRX = rdata[17] << 8 | rdata[16]; + pad->sThumbRY = rdata[19] << 8 | rdata[18]; + } + } + tuh_xinput_report_received_cb(dev_addr, instance, (const uint8_t *)&xid_itf->pad, sizeof(xinput_gamepad_t)); + } + else + { + if (tuh_xinput_report_sent_cb) + { + tuh_xinput_report_sent_cb(dev_addr, instance, xid_itf->epout_buf, xferred_bytes); + } + } + + + return true; +} + +void xinputh_close(uint8_t dev_addr) +{ + xinputh_device_t *xinput_dev = get_dev(dev_addr); + + for (uint8_t inst = 0; inst < xinput_dev->inst_count; inst++) + { + if (tuh_xinput_umount_cb) + { + tuh_xinput_umount_cb(dev_addr, inst); + } + } + tu_memclr(xinput_dev, sizeof(xinputh_device_t)); +} + +#endif diff --git a/src/lib/xinput_host.h b/src/lib/xinput_host.h new file mode 100644 index 00000000..804ebac3 --- /dev/null +++ b/src/lib/xinput_host.h @@ -0,0 +1,149 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#ifndef _TUSB_xinput_HOST_H_ +#define _TUSB_xinput_HOST_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// Class Driver Configuration +//--------------------------------------------------------------------+ + +#ifndef CFG_TUH_XINPUT_EPIN_BUFSIZE +#define CFG_TUH_XINPUT_EPIN_BUFSIZE 64 +#endif + +#ifndef CFG_TUH_XINPUT_EPOUT_BUFSIZE +#define CFG_TUH_XINPUT_EPOUT_BUFSIZE 64 +#endif + +//XINPUT defines and struct format from +//https://docs.microsoft.com/en-us/windows/win32/api/xinput/ns-xinput-xinput_gamepad +#define XINPUT_GAMEPAD_DPAD_UP 0x0001 +#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002 +#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004 +#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008 +#define XINPUT_GAMEPAD_START 0x0010 +#define XINPUT_GAMEPAD_BACK 0x0020 +#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040 +#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080 +#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 +#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 +#define XINPUT_GAMEPAD_A 0x1000 +#define XINPUT_GAMEPAD_B 0x2000 +#define XINPUT_GAMEPAD_X 0x4000 +#define XINPUT_GAMEPAD_Y 0x8000 +#define MAX_PACKET_SIZE 32 + +typedef struct xinput_gamepad +{ + uint16_t wButtons; + uint8_t bLeftTrigger; + uint8_t bRightTrigger; + int16_t sThumbLX; + int16_t sThumbLY; + int16_t sThumbRX; + int16_t sThumbRY; +} xinput_gamepad_t; + +typedef enum +{ + XINPUT_UNKNOWN = 0, + XBOXONE, + XBOX360_WIRELESS, + XBOX360_WIRED, + XBOXOG +} xinput_type_t; + +typedef struct +{ + xinput_type_t type; + xinput_gamepad_t pad; + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + uint16_t epin_size; + uint16_t epout_size; + + uint8_t epin_buf[CFG_TUH_XINPUT_EPIN_BUFSIZE]; + uint8_t epout_buf[CFG_TUH_XINPUT_EPOUT_BUFSIZE]; +} xinputh_interface_t; + +void tuh_xinput_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); +TU_ATTR_WEAK void tuh_xinput_report_sent_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); +TU_ATTR_WEAK void tuh_xinput_umount_cb(uint8_t dev_addr, uint8_t instance); +TU_ATTR_WEAK void tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, const tusb_desc_interface_t *desc_report); +bool tuh_xinput_receive_report(uint8_t dev_addr, uint8_t instance); +bool tuh_xinput_send_report(uint8_t dev_addr, uint8_t instance, const uint8_t *txbuf, uint16_t len); +bool tuh_xinput_set_led(uint8_t dev_addr, uint8_t instance, uint8_t quadrant, bool block); +bool tuh_xinput_set_rumble(uint8_t dev_addr, uint8_t instance, uint8_t lValue, uint8_t rValue, bool block); + +//--------------------------------------------------------------------+ +// Internal Class Driver API +//--------------------------------------------------------------------+ +void xinputh_init (void); +bool xinputh_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); +bool xinputh_set_config (uint8_t dev_addr, uint8_t itf_num); +bool xinputh_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); +void xinputh_close (uint8_t dev_addr); + +//Wired 360 commands +static const uint8_t xbox360_wired_rumble[] = {0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t xbox360_wired_led[] = {0x01, 0x03, 0x00}; + +//Xbone one +static const uint8_t xboxone_start_input[] = {0x05, 0x20, 0x03, 0x01, 0x00}; +static const uint8_t xboxone_s_init[] = {0x05, 0x20, 0x00, 0x0f, 0x06}; +static const uint8_t xboxone_pdp_init1[] = {0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14}; +static const uint8_t xboxone_pdp_init2[] = {0x06, 0x30}; +static const uint8_t xboxone_pdp_init3[] = {0x06, 0x20, 0x00, 0x02, 0x01, 0x00}; +static const uint8_t xboxone_rumble[] = {0x09, 0x00, 0x00, 0x09, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB}; + +//Wireless 360 commands +static const uint8_t xbox360w_led[] = {0x00, 0x00, 0x08, 0x40}; +//Sending 0x00, 0x00, 0x08, 0x00 will permanently disable rumble until you do this: +static const uint8_t xbox360w_rumble_enable[] = {0x00, 0x00, 0x08, 0x01}; +static const uint8_t xbox360w_rumble[] = {0x00, 0x01, 0x0F, 0xC0}; +static const uint8_t xbox360w_inquire_present[] = {0x08, 0x00, 0x0F, 0xC0}; +static const uint8_t xbox360w_controller_info[] = {0x00, 0x00, 0x00, 0x40}; +static const uint8_t xbox360w_unknown[] = {0x00, 0x00, 0x02, 0x80}; +static const uint8_t xbox360w_power_off[] = {0x00, 0x00, 0x08, 0xC0}; +static const uint8_t xbox360w_chatpad_init[] = {0x00, 0x00, 0x0C, 0x1B}; +static const uint8_t xbox360w_chatpad_keepalive1[] = {0x00, 0x00, 0x0C, 0x1F}; +static const uint8_t xbox360w_chatpad_keepalive2[] = {0x00, 0x00, 0x0C, 0x1E}; + +//Original Xbox +static const uint8_t xboxog_rumble[] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00}; + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_xinput_HOST_H_ */ From 2b4930536d4f43ec7f4af1ea22ce7f1b47f2ae10 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 12:25:51 +1030 Subject: [PATCH 020/121] Input: Rework for TinyUSB backend --- src/input.cpp | 768 +++++++++----------------------------------------- src/input.h | 32 ++- 2 files changed, 153 insertions(+), 647 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index 2ae81cdb..a12b7552 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -1,93 +1,89 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include -#include "USBHost_t36.h" #include "usb64_conf.h" #include "n64_controller.h" #include "input.h" #include "printf.h" #include "tft.h" +#include "tusb.h" -//USB Host Interface -USBHost usbh; - -#if (ENABLE_USB_HUB == 1) -USBHub hub1(usbh); -USBHub hub2(usbh); -USBHub hub3(usbh); -USBHub hub4(usbh); -#endif - -JoystickController joy1(usbh); -JoystickController joy2(usbh); -JoystickController joy3(usbh); -JoystickController joy4(usbh); -JoystickController joy5(usbh); -JoystickController joy6(usbh); -JoystickController joy7(usbh); -JoystickController joy8(usbh); - -USBHIDParser hid1(usbh); -USBHIDParser hid2(usbh); -USBHIDParser hid3(usbh); -USBHIDParser hid4(usbh); -MouseController mouse1(usbh); -MouseController mouse2(usbh); -MouseController mouse3(usbh); -MouseController mouse4(usbh); -KeyboardController kb1(usbh); -KeyboardController kb2(usbh); -KeyboardController kb3(usbh); -KeyboardController kb4(usbh); - -JoystickController *gamecontroller[] = {&joy1, &joy2, &joy3, &joy4, &joy5, &joy6, &joy7, &joy8}; -MouseController *mousecontroller[] = {&mouse1, &mouse2, &mouse3, &mouse4}; -KeyboardController *kbcontroller[] = {&kb1, &kb2, &kb3, &kb4}; +#define MAX_USB_CONTROLLERS (CFG_TUH_DEVICE_MAX) -uint32_t hardwired1; +input_driver_t input_devices[MAX_USB_CONTROLLERS]; -#define MAX_USB_CONTROLLERS (8) -static input input_devices[MAX_CONTROLLERS]; -static uint8_t kb_keys_pressed[RANDNET_MAX_BUTTONS]; +uint32_t hardwired1; -static void kb_pressed_cb(uint8_t keycode) +static input_driver_t *find_slot(uint16_t uid) { - //Check if its already pressed - for (int i = 0; i < RANDNET_MAX_BUTTONS; i++) + //See if input device already exists + for (int i = 0; i < MAX_USB_CONTROLLERS; i++) { - if (kb_keys_pressed[i] == keycode) + if (input_devices[i].uid == uid && uid > 0) { - return; + return &input_devices[i]; } } - //Register the keypress - for (int i = 0; i < RANDNET_MAX_BUTTONS; i++) + //Allocate new input device + for (int i = 0; i < MAX_USB_CONTROLLERS; i++) { - if (kb_keys_pressed[i] == 0) + if (input_devices[i].type == INPUT_NONE && uid == 0) { - kb_keys_pressed[i] = keycode; - break; + return &input_devices[i]; } } + return NULL; } -static void kb_released_cb(uint8_t keycode) +void tuh_xinput_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { - for (int i = 0; i < RANDNET_MAX_BUTTONS; i++) + uint16_t uid = dev_addr << 8 | instance; + input_driver_t *in_dev = find_slot(uid); + if (in_dev != NULL) { - if (kb_keys_pressed[i] == keycode) - { - kb_keys_pressed[i] = 0; - } + memcpy(in_dev->data, report, TU_MIN(len, CFG_TUH_XINPUT_EPIN_BUFSIZE)); + } + tuh_xinput_receive_report(dev_addr, instance); +} + +void tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, const tusb_desc_interface_t *desc_report) +{ + input_driver_t *in_dev = find_slot(0); + + in_dev->type = INPUT_GAMECONTROLLER; + in_dev->backend = BACKEND_XINPUT; + in_dev->uid = dev_addr << 8 | instance; + in_dev->set_rumble = tuh_xinput_set_rumble; + in_dev->set_led = tuh_xinput_set_led; + in_dev->data = in_dev->_data; + + tuh_xinput_set_led(dev_addr, instance, 0, true); + tuh_xinput_set_led(dev_addr, instance, 1, true); + tuh_xinput_set_rumble(dev_addr, instance, 0, 0, true); + printf("tuh_xinput_receive_report\n"); + if (tuh_xinput_receive_report(dev_addr, instance)) + { + printf("ok!\n"); + } +} + +void tuh_xinput_umount_cb(uint8_t dev_addr, uint8_t instance) +{ + uint16_t uid = dev_addr << 8 | instance; + input_driver_t *in_dev = find_slot(uid); + while (in_dev != NULL) + { + memset(in_dev, 0, sizeof(input_driver_t)); + in_dev = find_slot(uid); } } static int _check_id(uint8_t id) { - if (id > MAX_CONTROLLERS) + if (id >= MAX_USB_CONTROLLERS) return 0; - if (input_devices[id].driver == NULL) + + if (input_devices[id].backend == BACKEND_NONE) return 0; return 1; @@ -95,161 +91,17 @@ static int _check_id(uint8_t id) void input_init() { - usbh.begin(); - for (int i = 0; i < MAX_CONTROLLERS; i++) - { - input_devices[i].driver = NULL; - input_devices[i].type = USB_GAMECONTROLLER; - } + tusb_init(); + memset(input_devices, 0x00, sizeof(input_devices)); } void input_update_input_devices() { - //Clear disconnected devices - for (int i = 0; i < MAX_CONTROLLERS; i++) - { - if (input_is_connected(i) == 0) - { - if (input_devices[i].driver != NULL) - { - debug_print_status("[INPUT] Cleared device from slot %u\n", i); - tft_flag_update(); - } - input_devices[i].driver = NULL; - } - } - -#if (ENABLE_HARDWIRED_CONTROLLER >=1) - //Find hardwired game controller - if (digitalRead(HW_EN) == 0) - { - //Hardwired will always overwrite the first slot - if (input_devices[0].driver != &hardwired1) - { - input_devices[0].driver = &hardwired1; - input_devices[0].type = HW_GAMECONTROLLER; - debug_print_status("[INPUT] Registered hardwired gamecontroller to slot %u\n", 0); - tft_flag_update(); - } - } -#endif - - //Find new game controllers - for (uint32_t i = 0; i < MAX_USB_CONTROLLERS; i++) - { - //Game controller is connected - if (*(gamecontroller[i]) == true) - { - //Is it already a registered input device - bool already_registered = false; - for (int j = 0; j < MAX_CONTROLLERS; j++) - { - if (gamecontroller[i] == input_devices[j].driver) - { - already_registered = true; - break; - } - } - //Its a new controller, find empty slot and register it now - if (already_registered == false) - { - for (int j = 0; j < MAX_CONTROLLERS; j++) - { - if (input_devices[j].driver == NULL) - { - input_devices[j].driver = gamecontroller[i]; - input_devices[j].type = USB_GAMECONTROLLER; - debug_print_status("[INPUT] Registered gamecontroller to slot %u\n", j); - gamecontroller[i]->setLEDs(j + 2); - tft_flag_update(); - break; - } - } - } - } - } -#if (MAX_MICE >= 1) - //Find new mice - for (int i = 0; i < MAX_MICE; i++) - { - //Mouse is connected - USBHIDInput *m = (USBHIDInput *)mousecontroller[i]; - if (*m == true) - { - //Is it already a registered input device - bool already_registered = false; - for (int j = 0; j < MAX_CONTROLLERS; j++) - { - if (mousecontroller[i] == input_devices[j].driver) - { - already_registered = true; - break; - } - } - //Its a new mouse, find empty slot and register it now - if (already_registered == false) - { - for (int j = 0; j < MAX_CONTROLLERS; j++) - { - if (input_devices[j].driver == NULL) - { - input_devices[j].driver = mousecontroller[i]; - input_devices[j].type = USB_MOUSE; - debug_print_status("[INPUT] Register mouse to slot %u\n", j); - tft_flag_update(); - break; - } - } - } - } - } -#endif -#if (MAX_KB >= 1) - //Find new keyboard - for (int i = 0; i < MAX_KB; i++) - { - //Keyboard is connected - USBHIDInput *kb = (USBHIDInput *)kbcontroller[i]; - if (*kb == true) - { - //Is it already a registered input device - bool already_registered = false; - for (int j = 0; j < MAX_CONTROLLERS; j++) - { - if (kbcontroller[i] == input_devices[j].driver) - { - already_registered = true; - break; - } - } - //Its a new keyboard, find empty slot and register it now - if (already_registered == false) - { - for (int j = 0; j < MAX_CONTROLLERS; j++) - { - if (input_devices[j].driver == NULL) - { - input_devices[j].driver = kbcontroller[i]; - input_devices[j].type = USB_KB; - debug_print_status("[INPUT] Register keyboard to slot %u\n", j); - tft_flag_update(); - kbcontroller[i]->attachRawPress(kb_pressed_cb); - kbcontroller[i]->attachRawRelease(kb_released_cb); - break; - } - } - } - } - } -#endif + tuh_task(); } uint16_t input_get_state(uint8_t id, void *response, bool *combo_pressed) { - uint32_t _buttons = 0; - int32_t _axis[JoystickController::STANDARD_AXIS_COUNT] = {0}; - int32_t right_axis[2] = {0}; - *combo_pressed = 0; if (_check_id(id) == 0) @@ -258,199 +110,62 @@ uint16_t input_get_state(uint8_t id, void *response, bool *combo_pressed) if (response == NULL) return 0; - if (input_is(id, USB_GAMECONTROLLER)) + input_driver_t *in_dev = &input_devices[id]; + + if (in_dev == NULL) + return 0; + + if (input_is(id, INPUT_GAMECONTROLLER)) { //Prep N64 response n64_buttonmap *state = (n64_buttonmap *)response; state->dButtons = 0; - //Get latest info from USB devices - JoystickController *joy = (JoystickController *)input_devices[id].driver; - _buttons = joy->getButtons(); - - for (uint8_t i = 0; i < JoystickController::STANDARD_AXIS_COUNT; i++) + int32_t right_axis[2] = {0}; + if (in_dev->backend == BACKEND_XINPUT) { - _axis[i] = joy->getAxis(i); - } - joy->joystickDataClear(); + xinput_gamepad_t *pad = (xinput_gamepad_t *)in_dev->data; + if (pad->wButtons & XINPUT_GAMEPAD_DPAD_UP) state->dButtons |= N64_DU; //DUP + if (pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN) state->dButtons |= N64_DD; //DDOWN + if (pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT) state->dButtons |= N64_DL; //DLEFT + if (pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) state->dButtons |= N64_DR; //DRIGHT + if (pad->wButtons & XINPUT_GAMEPAD_START) state->dButtons |= N64_ST; //START + if (pad->wButtons & XINPUT_GAMEPAD_BACK) state->dButtons |= 0; //BACK + if (pad->wButtons & XINPUT_GAMEPAD_LEFT_THUMB) state->dButtons |= 0; //LS + if (pad->wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) state->dButtons |= 0; //RS + if (pad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) state->dButtons |= N64_LB; //LB + if (pad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) state->dButtons |= N64_RB; //RB + if (pad->wButtons & (1 << 10)) state->dButtons |= 0; //XBOX BUTTON + if (pad->wButtons & (1 << 11)) state->dButtons |= 0; //XBOX SYNC + if (pad->wButtons & XINPUT_GAMEPAD_A) state->dButtons |= N64_A; //A + if (pad->wButtons & XINPUT_GAMEPAD_B) state->dButtons |= N64_B; //B + if (pad->wButtons & XINPUT_GAMEPAD_X) state->dButtons |= N64_B; //X + if (pad->wButtons & XINPUT_GAMEPAD_Y) state->dButtons |= 0; //Y + if (pad->wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) state->dButtons |= N64_CU | //RS triggers + N64_CD | //all C usb_buttons + N64_CL | + N64_CR; - switch (joy->joystickType()) - { - case JoystickController::XBOX360: - case JoystickController::XBOX360_WIRED: - //Digital usb_buttons - //FIXME Modifier to make A,B,X,Y be C buttons - if (_buttons & (1 << 0)) state->dButtons |= N64_DU; //DUP - if (_buttons & (1 << 1)) state->dButtons |= N64_DD; //DDOWN - if (_buttons & (1 << 2)) state->dButtons |= N64_DL; //DLEFT - if (_buttons & (1 << 3)) state->dButtons |= N64_DR; //DRIGHT - if (_buttons & (1 << 4)) state->dButtons |= N64_ST; //START - if (_buttons & (1 << 5)) state->dButtons |= 0; //BACK - if (_buttons & (1 << 6)) state->dButtons |= 0; //LS - if (_buttons & (1 << 7)) state->dButtons |= 0; //RS - if (_buttons & (1 << 8)) state->dButtons |= N64_LB; //LB - if (_buttons & (1 << 9)) state->dButtons |= N64_RB; //RB - if (_buttons & (1 << 10)) state->dButtons |= 0; //XBOX BUTTON - if (_buttons & (1 << 11)) state->dButtons |= 0; //XBOX SYNC - if (_buttons & (1 << 12)) state->dButtons |= N64_A; //A - if (_buttons & (1 << 13)) state->dButtons |= N64_B; //B - if (_buttons & (1 << 14)) state->dButtons |= N64_B; //X - if (_buttons & (1 << 15)) state->dButtons |= 0; //Y - if (_buttons & (1 << 7)) state->dButtons |= N64_CU | //RS triggers - N64_CD | //all C usb_buttons - N64_CL | - N64_CR; //Analog stick (Normalise 0 to +/-100) - state->x_axis = _axis[0] * 100 / 32768; - state->y_axis = _axis[1] * 100 / 32768; + state->x_axis = pad->sThumbLX * 100 / 32768; + state->y_axis = pad->sThumbLY * 100 / 32768; //Z button - if (_axis[4] > 10) state->dButtons |= N64_Z; //LT - if (_axis[5] > 10) state->dButtons |= N64_Z; //RT + if (pad->bLeftTrigger > 10) state->dButtons |= N64_Z; //LT + if (pad->bRightTrigger > 10) state->dButtons |= N64_Z; //RT //C usb_buttons - if (_axis[2] > 16000) state->dButtons |= N64_CR; - if (_axis[2] < -16000) state->dButtons |= N64_CL; - if (_axis[3] > 16000) state->dButtons |= N64_CU; - if (_axis[3] < -16000) state->dButtons |= N64_CD; + if (pad->sThumbRX > 16000) state->dButtons |= N64_CR; + if (pad->sThumbRX < -16000) state->dButtons |= N64_CL; + if (pad->sThumbRY > 16000) state->dButtons |= N64_CU; + if (pad->sThumbRY < -16000) state->dButtons |= N64_CD; //Button to hold for 'combos' - if (combo_pressed) - *combo_pressed = (_buttons & (1 << 5)); //back + *combo_pressed = (pad->wButtons & XINPUT_GAMEPAD_BACK); //back //Map right axis for dual stick mode - right_axis[0] = _axis[2] * 100 / 32768; - right_axis[1] = _axis[3] * 100 / 32768; - - break; - case JoystickController::XBOXONE: - if (_buttons & (1 << 8)) state->dButtons |= N64_DU; //DUP - if (_buttons & (1 << 9)) state->dButtons |= N64_DD; //DDOWN - if (_buttons & (1 << 10)) state->dButtons |= N64_DL; //DLEFT - if (_buttons & (1 << 11)) state->dButtons |= N64_DR; //DRIGHT - if (_buttons & (1 << 2)) state->dButtons |= N64_ST; //START - if (_buttons & (1 << 3)) state->dButtons |= 0; //BACK - if (_buttons & (1 << 14)) state->dButtons |= 0; //LS - if (_buttons & (1 << 15)) state->dButtons |= 0; //RS - if (_buttons & (1 << 12)) state->dButtons |= N64_LB; //LB - if (_buttons & (1 << 13)) state->dButtons |= N64_RB; //RB - if (_buttons & (1 << 4)) state->dButtons |= N64_A; //A - if (_buttons & (1 << 5)) state->dButtons |= N64_B; //B - if (_buttons & (1 << 6)) state->dButtons |= N64_B; //X - if (_buttons & (1 << 7)) state->dButtons |= 0; //Y - if (_buttons & (1 << 15)) state->dButtons |= N64_CU | //RS triggers - N64_CD | //all C usb_buttons - N64_CL | - N64_CR; - //Analog stick (Normalise 0 to +/-100) - state->x_axis = _axis[0] * 100 / 32768; - state->y_axis = _axis[1] * 100 / 32768; - - //Z button - if (_axis[3] > 10) state->dButtons |= N64_Z; //LT - if (_axis[4] > 10) state->dButtons |= N64_Z; //RT - - //C usb_buttons - if (_axis[2] > 16000) state->dButtons |= N64_CR; - if (_axis[2] < -16000) state->dButtons |= N64_CL; - if (_axis[5] > 16000) state->dButtons |= N64_CU; - if (_axis[5] < -16000) state->dButtons |= N64_CD; - - //Button to hold for 'combos' - if (combo_pressed) - *combo_pressed = (_buttons & (1 << 3)); //back - - right_axis[0] = _axis[2] * 100 / 32768; - right_axis[1] = _axis[5] * 100 / 32768; - break; - case JoystickController::PS4: - if (_buttons & (1 << 9)) state->dButtons |= N64_ST; //START - if (_buttons & (1 << 4)) state->dButtons |= N64_LB; //L1 - if (_buttons & (1 << 5)) state->dButtons |= N64_RB; //R1 - if (_buttons & (1 << 6)) state->dButtons |= N64_Z; //L2 - if (_buttons & (1 << 7)) state->dButtons |= N64_Z; //R2 - if (_buttons & (1 << 1)) state->dButtons |= N64_A; //X - if (_buttons & (1 << 0)) state->dButtons |= N64_B; //SQUARE - if (_buttons & (1 << 2)) state->dButtons |= N64_B; //CIRCLE - if (_buttons & (1 << 11)) state->dButtons |= N64_CU | //RS triggers - N64_CD | //all C usb_buttons - N64_CL | - N64_CR; - //Analog stick (Normalise 0 to +/-100) - state->x_axis = (_axis[0] - 127) * 100 / 127; - state->y_axis = -(_axis[1] - 127) * 100 / 127; - - //D Pad button - switch(_axis[9]) - { - case 0: state->dButtons |= N64_DU; break; - case 1: state->dButtons |= N64_DU | N64_DR; break; - case 2: state->dButtons |= N64_DR; break; - case 3: state->dButtons |= N64_DR | N64_DD; break; - case 4: state->dButtons |= N64_DD; break; - case 5: state->dButtons |= N64_DD | N64_DL; break; - case 6: state->dButtons |= N64_DL; break; - case 7: state->dButtons |= N64_DL | N64_DU; break; - } - - //C usb_buttons - if (_axis[2] > 256/2 + 64) state->dButtons |= N64_CR; - if (_axis[2] < 256/2 - 64) state->dButtons |= N64_CL; - if (_axis[5] > 256/2 + 64) state->dButtons |= N64_CD; - if (_axis[5] < 256/2 - 64) state->dButtons |= N64_CU; - - //Button to hold for 'combos' - if (combo_pressed) - *combo_pressed = (_buttons & (1 << 8)); //back - - //Map right axis for dual stick mode - right_axis[0] = (_axis[2] - 127) * 100 / 127; - right_axis[1] = -(_axis[5] - 127) * 100 / 127; - break; - case JoystickController::UNKNOWN: - #if (0) - //Mapper helper - static uint32_t print_slower = 0; - if (millis() - print_slower > 100) - { - debug_print_status("%04x %04i %04i %04i %04i\n", _buttons, _axis[0], _axis[1], _axis[2], _axis[3]); - if (_buttons) - { - int bit = 0; - while ((_buttons & (1 << bit++)) == 0); - debug_print_status("button bit: %i\n", bit-1); - } - print_slower = millis(); - } - #endif - //Generic HID controllers //FIXME: Load from file? - //Example of a basic Chinese NES HID Controller. The button mapping nubmers are from a bit of trial and error. - //You can use the mapper helper above to assist. - //The controller doesnt have enough buttons, so we're missing alot here. - //NEXT SNES Controller - if (joy->idVendor() == 0x0810 && joy->idProduct() == 0xE501) - { - if (_buttons & (1 << 9)) state->dButtons |= N64_ST; - if (_buttons & (1 << 4)) state->dButtons |= N64_Z; - if (_buttons & (1 << 6)) state->dButtons |= N64_RB; - if (_buttons & (1 << 2)) state->dButtons |= N64_A; - if (_buttons & (1 << 1)) state->dButtons |= N64_B; - if (_buttons & (1 << 3)) state->dButtons |= N64_B; - - //Button to hold for 'combos' - if (combo_pressed) - *combo_pressed = (_buttons & (1 << 8)); //back - - //Analog stick (Normalise 0 to +/-100) - state->x_axis = (_axis[0] - 127) * 100 / 127; - state->y_axis = - (_axis[1] - 127) * 100 / 127; - } - break; - //TODO: OTHER USB CONTROLLERS - case JoystickController::PS3: - case JoystickController::PS3_MOTION: - default: - break; + right_axis[0] = pad->sThumbRX * 100 / 32768; + right_axis[1] = pad->sThumbRY * 100 / 32768; } //Use 2.4 GOODHEAD layout, axis not inverted @@ -480,300 +195,78 @@ uint16_t input_get_state(uint8_t id, void *response, bool *combo_pressed) state->dButtons |= N64_RES; } } -#if (MAX_MICE >= 1) - else if (input_is(id, USB_MOUSE)) - { - //Prep N64 response - n64_buttonmap *state = (n64_buttonmap *)response; - state->dButtons = 0; - - //Get latest info from USB devices - MouseController *mouse = (MouseController *)input_devices[id].driver; - _buttons = mouse->getButtons(); - - _axis[0] = mouse->getMouseX(); - _axis[1] = mouse->getMouseY(); - - static uint32_t idle_timer[4] = {0}; - if (mouse->available()) idle_timer[id] = millis(); - mouse->mouseDataClear(); - if (millis() - idle_timer[id] > 100) - { - _axis[0] = 0; - _axis[1] = 0; - } - - //Mouse input is pretty standard, Map to N64 mouse - if (_axis[0] * MOUSE_SENSITIVITY > 127) _axis[0] = 127; - if (_axis[1] * MOUSE_SENSITIVITY > 127) _axis[1] = 127; - if (_axis[0] * MOUSE_SENSITIVITY < -128) _axis[0] = -128; - if (_axis[1] * MOUSE_SENSITIVITY < -128) _axis[1] = -128; - state->x_axis = _axis[0] * MOUSE_SENSITIVITY; - state->y_axis = -_axis[1] * MOUSE_SENSITIVITY; - if (_buttons & (1 << 0)) state->dButtons |= N64_A; //A - if (_buttons & (1 << 1)) state->dButtons |= N64_B; //B - if (_buttons & (1 << 2)) state->dButtons |= N64_ST; //ST - } -#endif - -#if (MAX_KB >= 1) - else if (input_is(id, USB_KB)) - { - //Prep N64 response - n64_randnet_kb *state = (n64_randnet_kb *)response; - - //Get latest info from USB devices - KeyboardController *kb = (KeyboardController *)input_devices[id].driver; - - kb->capsLock((state->led_state & RANDNET_LED_CAPSLOCK) != 0); - kb->numLock((state->led_state & RANDNET_LED_NUMLOCK) != 0); - kb->scrollLock((state->led_state & RANDNET_LED_POWER) != 0); - uint8_t home_key_flag = 0; - //Map up to 3 keys to the randnet response packet - for (int i = 0; i < RANDNET_MAX_BUTTONS; i++) - { - state->buttons[i] = 0; - if (kb_keys_pressed[i] == 0) - continue; - - if (kb_keys_pressed[i] == (uint8_t)(KEY_HOME & 0xFF)) - { - home_key_flag = 1; - continue; - } - - //Keyboard is pressed, get the corressponding randnet code and put it in the response - uint16_t randnet_code = 0; - for (uint32_t j = 0; j < (sizeof(randnet_map) / sizeof(randnet_map_t)); j++) - { - if (kb_keys_pressed[i] == (uint8_t)(randnet_map[j].keypad & 0xFF)) - { - randnet_code = randnet_map[j].randnet_matrix; - } - } - state->buttons[i] = randnet_code; - } - - (home_key_flag) ? state->flags |= RANDNET_FLAG_HOME_KEY : - state->flags &= ~RANDNET_FLAG_HOME_KEY; - } -#endif - -#if (ENABLE_HARDWIRED_CONTROLLER >=1) - else if (input_is(id, HW_GAMECONTROLLER)) - { - n64_buttonmap *state = (n64_buttonmap *)response; - state->dButtons = 0; - - if (!digitalRead(HW_A)) state->dButtons |= N64_A; - if (!digitalRead(HW_B)) state->dButtons |= N64_B; - if (!digitalRead(HW_CU)) state->dButtons |= N64_CU; - if (!digitalRead(HW_CD)) state->dButtons |= N64_CD; - if (!digitalRead(HW_CL)) state->dButtons |= N64_CL; - if (!digitalRead(HW_CR)) state->dButtons |= N64_CR; - if (!digitalRead(HW_DU)) state->dButtons |= N64_DU; - if (!digitalRead(HW_DD)) state->dButtons |= N64_DD; - if (!digitalRead(HW_DL)) state->dButtons |= N64_DL; - if (!digitalRead(HW_DR)) state->dButtons |= N64_DR; - if (!digitalRead(HW_START)) state->dButtons |= N64_ST; - if (!digitalRead(HW_Z)) state->dButtons |= N64_Z; - if (!digitalRead(HW_L)) state->dButtons |= N64_LB; - if (!digitalRead(HW_R)) state->dButtons |= N64_RB; - - //10bit ADC - state->x_axis = analogRead(HW_X) * 200 / 1024 - 100; //+/-100 - state->y_axis = analogRead(HW_Y) * 200 / 1024 - 100; //+/-100 - - if (combo_pressed) - *combo_pressed = !digitalRead(HW_L) && !digitalRead(HW_R); //FIXME: ADD A COMBO INPUT? - } -#endif - else - { - return 0; - } return 1; } void input_apply_rumble(int id, uint8_t strength) { - JoystickController *joy; - if (input_is(id, USB_GAMECONTROLLER)) - { - joy = (JoystickController *)input_devices[id].driver; - joy->setRumble(strength, strength, 20); - } -#if (ENABLE_HARDWIRED_CONTROLLER >=1) - else if (input_is(id, HW_GAMECONTROLLER)) + if (_check_id(id) == 0) + return; + + input_driver_t *in_dev = &input_devices[id]; + if (in_dev->set_rumble) { - (strength > 0) ? digitalWrite(HW_RUMBLE, HIGH) : digitalWrite(HW_RUMBLE, LOW); + uint8_t dev_addr = in_dev->uid >> 8; + uint8_t instance = in_dev->uid & 0xFF; + in_dev->set_rumble(dev_addr, instance, strength, strength, true); } -#endif } bool input_is_connected(int id) { - bool connected = false; - if (_check_id(id) == 0) + if (id >= MAX_USB_CONTROLLERS) return false; - if (input_is(id, USB_GAMECONTROLLER)) - { - JoystickController *joy = (JoystickController *)input_devices[id].driver; - if (*joy == true) - connected = true; - } - -#if (MAX_MICE >=1) - else if (input_is(id, USB_MOUSE)) - { - USBHIDInput *mouse = (USBHIDInput *)input_devices[id].driver; - if (*mouse == true) - connected = true; - } -#endif - -#if (MAX_KB >=1) - else if (input_is(id, USB_KB)) - { - USBHIDInput *kb = (USBHIDInput *)input_devices[id].driver; - if (*kb == true) - connected = true; - } -#endif - -#if (ENABLE_HARDWIRED_CONTROLLER >=1) - else if (input_is(id, HW_GAMECONTROLLER)) - { - if (digitalRead(HW_EN) == 0) - connected = true; - } -#endif - - return connected; + return (input_devices[id].backend != BACKEND_NONE); } bool input_is(int id, input_type_t type) { - if (_check_id(id) == 0) + if (id >= MAX_USB_CONTROLLERS) return false; - if (input_devices[id].type == type) - return true; - return false; + + return (input_devices[id].type == type); } uint16_t input_get_id_product(int id) { - if (_check_id(id) == 0 || input_is_connected(id) == 0) - return 0; + if (_check_id(id) == 0) + return; - if (input_is(id, USB_GAMECONTROLLER)) - { - JoystickController *joy = (JoystickController *)input_devices[id].driver; - return joy->idProduct(); - } - else if (input_is(id, USB_MOUSE)) - { - USBHIDInput *mouse = (USBHIDInput *)input_devices[id].driver; - return mouse->idProduct(); - } - else if (input_is(id, USB_KB)) - { - USBHIDInput *kb = (USBHIDInput *)input_devices[id].driver; - return kb->idProduct(); - } - else if (input_is(id, HW_GAMECONTROLLER)) - { - return 0xBEEF; - } + input_driver_t *in_dev = &input_devices[id]; - return 0; + uint16_t pid, vid; + tuh_vid_pid_get(in_dev->uid >> 8, &vid, &pid); + return pid; } uint16_t input_get_id_vendor(int id) { - if (_check_id(id) == 0 || input_is_connected(id) == 0) - return 0; + if (_check_id(id) == 0) + return; - if (input_is(id, USB_GAMECONTROLLER)) - { - JoystickController *joy = (JoystickController *)input_devices[id].driver; - return joy->idVendor(); - } - else if (input_is(id, USB_MOUSE)) - { - USBHIDInput *mouse = (USBHIDInput *)input_devices[id].driver; - return mouse->idVendor(); - } - else if (input_is(id, USB_KB)) - { - USBHIDInput *kb = (USBHIDInput *)input_devices[id].driver; - return kb->idVendor(); - } - else if (input_is(id, HW_GAMECONTROLLER)) - { - return 0xDEAD; - } + input_driver_t *in_dev = &input_devices[id]; - return 0; + uint16_t pid, vid; + tuh_vid_pid_get(in_dev->uid >> 8, &vid, &pid); + return vid; } const char *input_get_manufacturer_string(int id) { + //FIXME static const char NC[] = "NOT CONNECTED"; if (_check_id(id) == 0 || input_is_connected(id) == false) return NC; - if (input_is(id, USB_GAMECONTROLLER)) - { - JoystickController *joy = (JoystickController *)input_devices[id].driver; - return (const char *)joy->manufacturer(); - } - else if (input_is(id, USB_MOUSE)) - { - USBHIDInput *mouse = (USBHIDInput *)input_devices[id].driver; - return (const char *)mouse->manufacturer(); - } - else if (input_is(id, USB_KB)) - { - USBHIDInput *kb = (USBHIDInput *)input_devices[id].driver; - return (const char *)kb->manufacturer(); - } - else if (input_is(id, HW_GAMECONTROLLER)) - { - return "USB64"; - } - - return NC; + return "USB64"; } const char *input_get_product_string(int id) { + //FIXME static const char NC[] = ""; - if (_check_id(id) == 0 || input_is_connected(id) == 0) - return NC; - - if (input_is(id, USB_GAMECONTROLLER)) - { - JoystickController *joy = (JoystickController *)input_devices[id].driver; - return (const char *)joy->product(); - } - else if (input_is(id, USB_MOUSE)) - { - USBHIDInput *mouse = (USBHIDInput *)input_devices[id].driver; - return (const char *)mouse->product(); - } - else if (input_is(id, USB_KB)) - { - USBHIDInput *kb = (USBHIDInput *)input_devices[id].driver; - return (const char *)kb->product(); - } - else if (input_is(id, HW_GAMECONTROLLER)) - { - return "HARDWIRED"; - } - return NC; } @@ -787,7 +280,7 @@ void input_enable_dualstick_mode(int id) return; //Copy driver into the next slot to make a 'fake' input - memcpy(&input_devices[id + 1], &input_devices[id], sizeof(input)); + memcpy(&input_devices[id + 1], &input_devices[id], sizeof(input_driver_t)); } void input_disable_dualstick_mode(int id) @@ -799,8 +292,7 @@ void input_disable_dualstick_mode(int id) return; //Clear the 'fake' controller driver - input_devices[id + 1].driver = NULL; - + memset(&input_devices[id + 1], 0, sizeof(input_driver_t )); } bool input_is_dualstick_mode(int id) @@ -809,14 +301,14 @@ bool input_is_dualstick_mode(int id) return false; //Check if this is a 'fake' mirror of a main controller - if ((id == 1 || id == 3) && input_devices[id].driver == input_devices[id - 1].driver) + if ((id == 1 || id == 3) && input_devices[id].uid == input_devices[id - 1].uid) return true; if (id + 1 >= MAX_CONTROLLERS) return false; //Check if this is a main controller that is mirrored - if (input_devices[id].driver == input_devices[id + 1].driver) + if (input_devices[id].uid == input_devices[id + 1].uid) return true; return false; diff --git a/src/input.h b/src/input.h index a003df90..5f1e3f31 100644 --- a/src/input.h +++ b/src/input.h @@ -4,7 +4,8 @@ #ifndef _INPUT_H #define _INPUT_H -#include +#include "usb64_conf.h" +#include "tusb.h" typedef struct { @@ -101,18 +102,31 @@ static const randnet_map_t randnet_map[] = { typedef enum { - USB_MOUSE, - USB_KB, - USB_GAMECONTROLLER, - HW_GAMECONTROLLER, - I2C_GAMECONTROLLER + INPUT_NONE, + INPUT_MOUSE, + INPUT_KEYBOARD, + INPUT_GAMECONTROLLER, } input_type_t; -typedef struct +typedef enum input_backend +{ + BACKEND_NONE, + BACKEND_XINPUT, + BACKEND_HID_KEYBOARD, + BACKEND_HID_MOUSE, + BACKEND_HARDWIRED, +} input_backend_t; + +typedef struct input_driver { - void *driver; input_type_t type; -} input; + input_backend_t backend; + uint8_t _data[CFG_TUH_XINPUT_EPIN_BUFSIZE]; + uint8_t *data; + uint16_t uid; + bool (*set_rumble)(uint8_t dev_addr, uint8_t instance, uint8_t lValue, uint8_t rValue, bool block); + bool (*set_led)(uint8_t dev_addr, uint8_t instance, uint8_t quadrant, bool block); +}input_driver_t; void input_init(); void input_update_input_devices(); From c3a540c182a00b87a92b2080a27d967ea6dfd005 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 12:27:35 +1030 Subject: [PATCH 021/121] Main: Update for new input backend --- src/main.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 942c9ec4..8980be28 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,7 @@ #include "tft.h" #include "n64_wrapper.h" +void usbh_dev_init(void); static void ring_buffer_init(void); static void ring_buffer_flush(); @@ -64,6 +65,16 @@ void startup_early_hook(void) } #endif +#ifdef CFG_TUSB_DEBUG_PRINTF +extern "C" int CFG_TUSB_DEBUG_PRINTF(const char *format, ...) +{ + va_list args; + va_start(args, format); + vprintf(format, args); + return 1; +} +#endif + #ifndef ARDUINO #include #include @@ -85,6 +96,7 @@ void setup() ring_buffer_init(); fileio_init(); memory_init(); + usbh_dev_init(); input_init(); tft_init(); n64_subsystem_init(n64_in_dev); @@ -166,7 +178,7 @@ void loop() } n64_in_dev[c].interrupt_attached = true; } - if (input_is(c, USB_GAMECONTROLLER)) + if (input_is(c, INPUT_GAMECONTROLLER)) { n64_buttonmap *new_state = (n64_buttonmap *)n64_response[c]; input_get_state(c, new_state, &n64_combo); @@ -206,7 +218,7 @@ void loop() } } #if (MAX_MICE >= 1) - else if (input_is(c, USB_MOUSE)) + else if (input_is(c, INPUT_MOUSE)) { n64_buttonmap *new_state = (n64_buttonmap *)n64_response[c]; input_get_state(c, new_state, &n64_combo); @@ -222,7 +234,7 @@ void loop() } #endif #if (MAX_KB >= 1) - else if (input_is(c, USB_KB)) + else if (input_is(c, INPUT_KEYBOARD)) { n64_randnet_kb *new_state = (n64_randnet_kb *)n64_response[c]; //Maintain the old led state @@ -248,7 +260,7 @@ void loop() //Get a copy of the latest n64 button presses to handle the below combos uint16_t n64_buttons = 0; - if (input_is(c, USB_GAMECONTROLLER)) + if (input_is(c, INPUT_GAMECONTROLLER)) { n64_buttonmap *new_state = (n64_buttonmap *)n64_response[c]; n64_buttons = new_state->dButtons; From 348095d220074dbc9994aded05787ccca8865b01 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 12:34:19 +1030 Subject: [PATCH 022/121] Build: Update CI for TinyUSB --- .github/workflows/build.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7f266fa9..a01499c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,9 +20,18 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@v1 - with: - submodules: recursive + - name: Get submoduiles + run: | + git submodule init + git submodule update + # If manually get TinyUSBs submodules we need otherwise its a huge repo + cd src/lib/tinyusb + # Teensy41 Specific + git submodule init hw/mcu/nxp/mcux-sdk + git submodule update + cd ../../../ + - name: Set up Python uses: actions/setup-python@v1 From 9dbdb3433d84c8637f35b6e1e186344dde59c4e4 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 12:40:52 +1030 Subject: [PATCH 023/121] USBH: Disable debug output --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 3f51430a..7e7fca87 100644 --- a/platformio.ini +++ b/platformio.ini @@ -43,7 +43,7 @@ build_flags = -Isrc/lib/printf -Isrc/lib/tinyusb/src -DCFG_TUSB_DEBUG_PRINTF="tusb_printf_hook" - -DCFG_TUSB_DEBUG=2 + -DCFG_TUSB_DEBUG=0 ; Printf Configuration -DPRINTF_DISABLE_SUPPORT_FLOAT From 43891221d6295eee0632bc760441935ca0141b75 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 15:20:26 +1030 Subject: [PATCH 024/121] Input: Fix warnings and remove debug messages --- src/input.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index a12b7552..0864f3e1 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -4,7 +4,6 @@ #include "usb64_conf.h" #include "n64_controller.h" #include "input.h" -#include "printf.h" #include "tft.h" #include "tusb.h" @@ -60,11 +59,7 @@ void tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, const tusb_desc_int tuh_xinput_set_led(dev_addr, instance, 0, true); tuh_xinput_set_led(dev_addr, instance, 1, true); tuh_xinput_set_rumble(dev_addr, instance, 0, 0, true); - printf("tuh_xinput_receive_report\n"); - if (tuh_xinput_receive_report(dev_addr, instance)) - { - printf("ok!\n"); - } + tuh_xinput_receive_report(dev_addr, instance); } void tuh_xinput_umount_cb(uint8_t dev_addr, uint8_t instance) @@ -232,7 +227,7 @@ bool input_is(int id, input_type_t type) uint16_t input_get_id_product(int id) { if (_check_id(id) == 0) - return; + return 0; input_driver_t *in_dev = &input_devices[id]; @@ -244,7 +239,7 @@ uint16_t input_get_id_product(int id) uint16_t input_get_id_vendor(int id) { if (_check_id(id) == 0) - return; + return 0; input_driver_t *in_dev = &input_devices[id]; From 1a1b3498ea72cc46aeb5c0fd75e18db379d80458 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 15:20:52 +1030 Subject: [PATCH 025/121] Input: Replace ASCII defines with TinyUSB --- src/input.h | 162 ++++++++++++++++++++++++++-------------------------- 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/src/input.h b/src/input.h index 5f1e3f31..97db0dc1 100644 --- a/src/input.h +++ b/src/input.h @@ -14,90 +14,90 @@ typedef struct } randnet_map_t; static const randnet_map_t randnet_map[] = { - {KEY_ESC, 0x0A08}, //Escape - {KEY_F1, 0x0B01}, // F1 - {KEY_F2, 0x0A01}, // F2 - {KEY_F3, 0x0B08}, // F3 - {KEY_F4, 0x0A07}, // F4 - {KEY_F5, 0x0B07}, // F5 - {KEY_F6, 0x0A02}, // F6 - {KEY_F7, 0x0B02}, // F7 - {KEY_F8, 0x0A03}, // F8 - {KEY_F9, 0x0B03}, // F9 - {KEY_F10, 0x0A04}, // F10 - {KEY_F11, 0x0203}, // F11 - {KEY_F12, 0x0B06}, // F12 - {KEY_NUM_LOCK, 0x0A05}, // Num Lock - {KEY_PRINTSCREEN, 0x0B05}, //Japanese Key below Numlock LED - {KEY_SCROLL_LOCK, 0x0208}, //Japanese Key below Caps Lock LED - {KEY_PAUSE, 0x0207}, // Japanese Key below Power LED - {KEY_TILDE, 0x0D05}, //~ - {KEY_1, 0x0C05}, //Number 1 - {KEY_2, 0x0505}, //Number 2 - {KEY_3, 0x0605}, //Number 3 - {KEY_4, 0x0705}, //Number 4 - {KEY_5, 0x0805}, //Number 5 - {KEY_6, 0x0905}, //Number 6 - {KEY_7, 0x0906}, //Number 7 - {KEY_8, 0x0806}, //Number 8 - {KEY_9, 0x0706}, //Number 9 - {KEY_0, 0x0606}, //Number 0 - {KEYPAD_MINUS, 0x0506}, //- - {KEYPAD_PLUS, 0x0C06}, //^ - {KEY_BACKSPACE, 0x0D06}, //Backspace - {KEY_TAB, 0x0D01}, //Tab - {KEY_Q, 0x0C01}, //Q - {KEY_W, 0x0501}, //W - {KEY_E, 0x0601}, //E - {KEY_R, 0x0701}, //R - {KEY_T, 0x0801}, //T - {KEY_Y, 0x0901}, //Y - {KEY_U, 0x0904}, //U - {KEY_I, 0x0804}, //I - {KEY_O, 0x0704}, //O - {KEY_P, 0x0604}, //P - {KEY_QUOTE, 0x0504}, //' - {KEY_LEFT_BRACE, 0x0C04}, //{ - {KEY_RIGHT_BRACE, 0x0406}, //} - {KEY_CAPS_LOCK, 0x0F05}, //Caps Lock - {KEY_A, 0x0D07}, //A - {KEY_S, 0x0C07}, //S - {KEY_D, 0x0507}, //D - {KEY_F, 0x0607}, //F - {KEY_G, 0x0707}, //G - {KEY_H, 0x0807}, //H - {KEY_J, 0x0907}, //J - {KEY_K, 0x0903}, //K - {KEY_L, 0x0803}, //L - {KEYPAD_PLUS, 0x0703}, //+ - {KEYPAD_ASTERIX, 0x0603}, //* - {KEY_ENTER, 0x0D04}, //Enter - {104, 0x0E01}, //Left Shift - {KEY_Z, 0x0D08}, //Z - {KEY_X, 0x0C08}, //X - {KEY_C, 0x0508}, //C - {KEY_V, 0x0608}, //V - {KEY_B, 0x0708}, //B - {KEY_N, 0x0808}, //N - {KEY_M, 0x0908}, //M - {KEY_COMMA, 0x0902}, //< - {KEY_PERIOD, 0x0802}, //> - {KEY_SLASH, 0x0702}, //? - {KEY_MINUS, 0x1004}, //- (Long dash) - {KEY_UP, 0x0204}, //Up Cursor - {104, 0x0E06}, //Right Shift + {HID_KEY_ESCAPE, 0x0A08}, //Escape + {HID_KEY_F1, 0x0B01}, // F1 + {HID_KEY_F2, 0x0A01}, // F2 + {HID_KEY_F3, 0x0B08}, // F3 + {HID_KEY_F4, 0x0A07}, // F4 + {HID_KEY_F5, 0x0B07}, // F5 + {HID_KEY_F6, 0x0A02}, // F6 + {HID_KEY_F7, 0x0B02}, // F7 + {HID_KEY_F8, 0x0A03}, // F8 + {HID_KEY_F9, 0x0B03}, // F9 + {HID_KEY_F10, 0x0A04}, // F10 + {HID_KEY_F11, 0x0203}, // F11 + {HID_KEY_F12, 0x0B06}, // F12 + {HID_KEY_NUM_LOCK, 0x0A05}, // Num Lock + {HID_KEY_PRINT_SCREEN, 0x0B05}, //Japanese Key below Numlock LED + {HID_KEY_SCROLL_LOCK, 0x0208}, //Japanese Key below Caps Lock LED + {HID_KEY_PAUSE, 0x0207}, // Japanese Key below Power LED + {HID_KEY_GRAVE, 0x0D05}, //~ + {HID_KEY_1, 0x0C05}, //Number 1 + {HID_KEY_2, 0x0505}, //Number 2 + {HID_KEY_3, 0x0605}, //Number 3 + {HID_KEY_4, 0x0705}, //Number 4 + {HID_KEY_5, 0x0805}, //Number 5 + {HID_KEY_6, 0x0905}, //Number 6 + {HID_KEY_7, 0x0906}, //Number 7 + {HID_KEY_8, 0x0806}, //Number 8 + {HID_KEY_9, 0x0706}, //Number 9 + {HID_KEY_0, 0x0606}, //Number 0 + {HID_KEY_KEYPAD_SUBTRACT, 0x0506}, //- + {HID_KEY_KEYPAD_ADD, 0x0C06}, //^ + {HID_KEY_BACKSPACE, 0x0D06}, //Backspace + {HID_KEY_TAB, 0x0D01}, //Tab + {HID_KEY_Q, 0x0C01}, //Q + {HID_KEY_W, 0x0501}, //W + {HID_KEY_E, 0x0601}, //E + {HID_KEY_R, 0x0701}, //R + {HID_KEY_T, 0x0801}, //T + {HID_KEY_Y, 0x0901}, //Y + {HID_KEY_U, 0x0904}, //U + {HID_KEY_I, 0x0804}, //I + {HID_KEY_O, 0x0704}, //O + {HID_KEY_P, 0x0604}, //P + {HID_KEY_APOSTROPHE, 0x0504}, //' + {HID_KEY_BRACKET_LEFT, 0x0C04}, //{ + {HID_KEY_BRACKET_RIGHT, 0x0406}, //} + {HID_KEY_CAPS_LOCK, 0x0F05}, //Caps Lock + {HID_KEY_A, 0x0D07}, //A + {HID_KEY_S, 0x0C07}, //S + {HID_KEY_D, 0x0507}, //D + {HID_KEY_F, 0x0607}, //F + {HID_KEY_G, 0x0707}, //G + {HID_KEY_H, 0x0807}, //H + {HID_KEY_J, 0x0907}, //J + {HID_KEY_K, 0x0903}, //K + {HID_KEY_L, 0x0803}, //L + {HID_KEY_KEYPAD_ADD, 0x0703}, //+ + {HID_KEY_KEYPAD_MULTIPLY, 0x0603}, //* + {HID_KEY_ENTER, 0x0D04}, //Enter + {HID_KEY_SHIFT_LEFT, 0x0E01}, //Left Shift + {HID_KEY_Z, 0x0D08}, //Z + {HID_KEY_X, 0x0C08}, //X + {HID_KEY_C, 0x0508}, //C + {HID_KEY_V, 0x0608}, //V + {HID_KEY_B, 0x0708}, //B + {HID_KEY_N, 0x0808}, //N + {HID_KEY_M, 0x0908}, //M + {HID_KEY_COMMA, 0x0902}, //< + {HID_KEY_PERIOD, 0x0802}, //> + {HID_KEY_SLASH, 0x0702}, //? + {HID_KEY_MINUS, 0x1004}, //- (Long dash) + {HID_KEY_ARROW_UP, 0x0204}, //Up Cursor + {HID_KEY_SHIFT_RIGHT, 0x0E06}, //Right Shift {103, 0x1107}, //Ctrl {110, 0x0F07}, //Opt - {KEY_SEMICOLON, 0x1105}, //| (Pipes) + {HID_KEY_SEMICOLON, 0x1105}, //| (Pipes) {105, 0x1008}, //Alt - {KEYPAD_1, 0x1002}, //Japanese 'alphanumeric key' - {KEY_SPACE, 0x0602}, //Space - {KEYPAD_2, 0x0E02}, //Japanese 'kana' - {KEYPAD_3, 0x1006}, //Japanese Character - {KEY_END, 0x0206}, //End 行末 - {KEY_LEFT, 0x0205}, //Left Cursor - {KEY_DOWN, 0x0305}, //Down Cursor - {KEY_RIGHT, 0x0405}, //Right Cursor + {HID_KEY_KEYPAD_1, 0x1002}, //Japanese 'alphanumeric key' + {HID_KEY_SPACE, 0x0602}, //Space + {HID_KEY_KEYPAD_2, 0x0E02}, //Japanese 'kana' + {HID_KEY_KEYPAD_3, 0x1006}, //Japanese Character + {HID_KEY_END, 0x0206}, //End 行末 + {HID_KEY_ARROW_LEFT, 0x0205}, //Left Cursor + {HID_KEY_ARROW_DOWN, 0x0305}, //Down Cursor + {HID_KEY_ARROW_RIGHT, 0x0405}, //Right Cursor }; typedef enum From caeab5433225ecca00aa8f65bee44a4ccffc6761 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 15:22:22 +1030 Subject: [PATCH 026/121] FileIO: Return 0 on success --- src/fileio.cpp | 8 ++++---- src/teensy41/fileio_t4.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index ee6f53b2..b150d66f 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -81,9 +81,9 @@ void fileio_write_to_file(char *filename, uint8_t *data, uint32_t len) { debug_print_error("[FILEIO] ERROR: Could not write %s\n", filename); } - else if (ret == -3) + else { - debug_print_status("[FILEIO] Writing %s for %lu bytes ok!\n", filename, len); + debug_print_status("[FILEIO] Writing %s for %u bytes ok!\n", filename, len); } } @@ -110,9 +110,9 @@ void fileio_read_from_file(char *filename, uint32_t file_offset, uint8_t *data, { debug_print_error("[FILEIO] ERROR: Could not read %s\n", filename); } - else if (ret == -3) + else { - debug_print_status("[FILEIO] Reading %s for %lu bytes ok!\n", filename, len); + debug_print_status("[FILEIO] Reading %s for %u bytes ok!\n", filename, len); } } diff --git a/src/teensy41/fileio_t4.cpp b/src/teensy41/fileio_t4.cpp index 914274f7..9bc8a963 100644 --- a/src/teensy41/fileio_t4.cpp +++ b/src/teensy41/fileio_t4.cpp @@ -61,7 +61,7 @@ int fileio_dev_read(char *filename, uint32_t file_offset, uint8_t *data, uint32_ } else { - return -3; + return 0; } fil.close(); } @@ -79,7 +79,7 @@ int fileio_dev_write(char *filename, uint8_t *data, uint32_t len) } else { - return -3; + return 0; } fil.close(); } From 87e7d719050e8e96438191ea233307d1d896dd46 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 15:23:40 +1030 Subject: [PATCH 027/121] HAL: Add milli tick wrapper --- src/n64_wrapper.h | 2 ++ src/teensy41/hal_t4.cpp | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/n64_wrapper.h b/src/n64_wrapper.h index 45b05bff..143678ff 100644 --- a/src/n64_wrapper.h +++ b/src/n64_wrapper.h @@ -8,6 +8,7 @@ extern "C" { #endif +#include "usb64_conf.h" #include "n64_controller.h" #define N64_OUTPUT 1 @@ -36,6 +37,7 @@ void n64hal_rtc_write(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t * uint32_t n64hal_hs_tick_get_speed(); void n64hal_hs_tick_init(); uint32_t n64hal_hs_tick_get(); +uint32_t n64hal_millis(); //RAM access wrappers void n64hal_read_extram(void *rx_buff, void *src, uint32_t offset, uint32_t len); diff --git a/src/teensy41/hal_t4.cpp b/src/teensy41/hal_t4.cpp index 46437575..052d2ed9 100644 --- a/src/teensy41/hal_t4.cpp +++ b/src/teensy41/hal_t4.cpp @@ -106,6 +106,11 @@ uint32_t n64hal_hs_tick_get() return ARM_DWT_CYCCNT; } +uint32_t n64hal_millis() +{ + return millis(); +} + /* * Function: Flips the gpio pin direction from an output (driven low) to an input (pulled up) * for the controller passed by controller. From cd6214d932e81a75d916e845f8474ac820c1a428 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 15:24:41 +1030 Subject: [PATCH 028/121] Conf: Fix printf wrapper linkage errors --- src/usb64_conf.h | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/usb64_conf.h b/src/usb64_conf.h index 9980996e..9c88c062 100644 --- a/src/usb64_conf.h +++ b/src/usb64_conf.h @@ -9,7 +9,13 @@ #include #include #include + #include "printf.h" +#undef printf +#undef sprintf +#undef snprinf +#undef vsnprintf +#undef vprintf #ifndef _USB64_CONF_h #define _USB64_CONF_h @@ -101,11 +107,12 @@ #endif /* DEBUG PRINTERS */ -#define debug_print_status(fmt, ...) do { if (DEBUG_STATUS) printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_n64(fmt, ...) do { if (DEBUG_N64) printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_tpak(fmt, ...) do { if (DEBUG_TPAK) printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_usbhost(fmt, ...) do { if (DEBUG_USBHOST) printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_fatfs(fmt, ...) do { if (DEBUG_FATFS) printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_memory(fmt, ...) do { if (DEBUG_MEMORY) printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_error(fmt, ...) do { if (DEBUG_ERROR) printf(fmt, ##__VA_ARGS__); } while (0) -#endif +#define debug_print_status(fmt, ...) do { if (DEBUG_STATUS) printf_(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_n64(fmt, ...) do { if (DEBUG_N64) printf_(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_tpak(fmt, ...) do { if (DEBUG_TPAK) printf_(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_usbhost(fmt, ...) do { if (DEBUG_USBHOST) printf_(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_fatfs(fmt, ...) do { if (DEBUG_FATFS) printf_(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_memory(fmt, ...) do { if (DEBUG_MEMORY) printf_(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_error(fmt, ...) do { if (DEBUG_ERROR) printf_(fmt, ##__VA_ARGS__); } while (0) + +#endif \ No newline at end of file From 06015cd41dee0f4dcf8de2549d53984cb066cc27 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 15:29:07 +1030 Subject: [PATCH 029/121] usb64: Fix warnings --- src/main.cpp | 18 ++++++------------ src/memory.cpp | 10 +++++----- src/n64/n64_controller.h | 1 + src/n64/n64_transferpak_gbcarts.c | 4 ++-- src/n64/n64_virtualpak.c | 12 ++++++------ src/tft.cpp | 5 ++--- 6 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8980be28..98bbdd7d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -76,6 +76,8 @@ extern "C" int CFG_TUSB_DEBUG_PRINTF(const char *format, ...) #endif #ifndef ARDUINO +void setup(); +void loop(); #include #include #include @@ -294,7 +296,7 @@ void loop() //Handle ram flushing. Auto flushes when the N64 is turned off :) static uint32_t flushing_toggle[MAX_CONTROLLERS] = {0}; - n64_is_on = digitalRead(N64_CONSOLE_SENSE); + n64_is_on = n64hal_input_read(N64_CONSOLE_SENSE); if ((n64_combo && (n64_buttons & N64_A)) || (n64_is_on == 0)) { if (flushing_toggle[c] == 0) @@ -328,14 +330,6 @@ void loop() { tft_toggle[c] = 0; } - - //Measure Teensy temp and if it has changed, flag a TFT update - static int32_t teensy_temp = 0; - if (abs((int32_t)tempmonGetTemp() - teensy_temp) > 2) - { - teensy_temp = (int32_t)tempmonGetTemp(); - tft_flag_update(); - } #endif //Handle peripheral change combinations @@ -351,7 +345,7 @@ void loop() if (n64_in_dev[c].current_peripheral == PERI_NONE) break; //Already changing peripheral - timer_peri_change[c] = millis(); + timer_peri_change[c] = n64hal_millis(); /* CLEAR CURRENT PERIPHERALS */ if (n64_in_dev[c].mempack != NULL) @@ -504,7 +498,7 @@ void loop() //Simulate a peripheral change time. The peripheral goes to NONE //for a short period. Some games need this. - if (n64_in_dev[c].current_peripheral == PERI_NONE && (millis() - timer_peri_change[c]) > PERI_CHANGE_TIME) + if (n64_in_dev[c].current_peripheral == PERI_NONE && (n64hal_millis() - timer_peri_change[c]) > PERI_CHANGE_TIME) { n64_in_dev[c].current_peripheral = n64_in_dev[c].next_peripheral; tft_flag_update(); @@ -535,7 +529,7 @@ void loop() /* PRINTF HANDLING */ static uint32_t ring_buffer_pos = 0; static char ring_buffer[4096]; -void _putchar(char character) +extern "C" void _putchar(char character) { ring_buffer[ring_buffer_pos] = character; tft_add_log(character); diff --git a/src/memory.cpp b/src/memory.cpp index 5d67d7f2..5ae2b215 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -50,7 +50,7 @@ uint8_t *memory_alloc_ram(const char *name, uint32_t alloc_len, uint32_t read_on //Already malloced, check len is ok if (sram[i].len <= alloc_len) { - debug_print_memory("[MEMORY] Memory already malloced for %s at 0x%08x, returning pointer to it\n", name, sram[i].data); + debug_print_memory("[MEMORY] Memory already malloced for %s at 0x%llx, returning pointer to it\n", name, (uintptr_t)sram[i].data); return sram[i].data; } @@ -82,7 +82,7 @@ uint8_t *memory_alloc_ram(const char *name, uint32_t alloc_len, uint32_t read_on sram[i].read_only = read_only; sram[i].dirty = 0; - debug_print_memory("[MEMORY] Alloc'd %s, %u bytes at 0x%08x\n", sram[i].name, sram[i].len, sram[i].data); + debug_print_memory("[MEMORY] Alloc'd %s, %u bytes at 0x%llx\n", sram[i].name, sram[i].len, (uintptr_t)sram[i].data); return sram[i].data; } } @@ -100,7 +100,7 @@ void memory_free_item(void *ptr) { if (sram[i].data == ptr) { - debug_print_memory("[MEMORY] Freeing %s at 0x%08x\n", sram[i].name, sram[i].data); + debug_print_memory("[MEMORY] Freeing %s at 0x%llx\n", sram[i].name, (uintptr_t)sram[i].data); memory_dev_free(sram[i].data); sram[i].name[0] = '\0'; sram[i].data = NULL; @@ -109,7 +109,7 @@ void memory_free_item(void *ptr) return; } } - debug_print_memory("[MEMORY] WARNING: Did not free 0x%08x\n", ptr); + debug_print_memory("[MEMORY] WARNING: Did not free 0x%llx\n", (uintptr_t)ptr); } //Flush SRAM to flash memory if required @@ -142,5 +142,5 @@ void memory_mark_dirty(void *ptr) return; } } - debug_print_error("[MEMORY] ERROR: Could not find 0x%08x\n", ptr); + debug_print_error("[MEMORY] ERROR: Could not find 0x%llx\n", (uintptr_t)ptr); } diff --git a/src/n64/n64_controller.h b/src/n64/n64_controller.h index 00e0c68c..6f152885 100644 --- a/src/n64/n64_controller.h +++ b/src/n64/n64_controller.h @@ -8,6 +8,7 @@ extern "C" { #endif +#include "usb64_conf.h" #include "n64_mempak.h" #include "n64_rumblepak.h" #include "n64_transferpak_gbcarts.h" diff --git a/src/n64/n64_transferpak_gbcarts.c b/src/n64/n64_transferpak_gbcarts.c index e9f2a056..eda6e174 100644 --- a/src/n64/n64_transferpak_gbcarts.c +++ b/src/n64/n64_transferpak_gbcarts.c @@ -320,8 +320,8 @@ void gb_init_cart(gameboycart *cart, uint8_t *gb_header, char *filename) memcpy(cart->filename, filename, sizeof(cart->filename)); debug_print_tpak("[TPAK] gb_init_cart: GB Name: %.15s\n", cart->title); - debug_print_tpak("[TPAK] gb_init_cart: ROM Bytes: %lu\n", cart->romsize); - debug_print_tpak("[TPAK] gb_init_cart: SRAM Bytes: %lu\n", cart->ramsize); + debug_print_tpak("[TPAK] gb_init_cart: ROM Bytes: %u\n", cart->romsize); + debug_print_tpak("[TPAK] gb_init_cart: SRAM Bytes: %u\n", cart->ramsize); debug_print_tpak("[TPAK] gb_init_cart: MBC Type: 0x%02x\n", cart->mbc); } diff --git a/src/n64/n64_virtualpak.c b/src/n64/n64_virtualpak.c index 30b340e2..e8da29e0 100644 --- a/src/n64/n64_virtualpak.c +++ b/src/n64/n64_virtualpak.c @@ -396,16 +396,16 @@ void n64_virtualpak_update(n64_mempack *vpak) } //Print the current values of each setting - sprintf(buff, "%u\0", settings->sensitivity[controller_page]); + sprintf(buff, "%u", settings->sensitivity[controller_page]); n64_virtualpak_write_string(buff, SUBHEADING + 4, MENU_EXT_FIELD); - sprintf(buff, "%u\0", settings->deadzone[controller_page]); + sprintf(buff, "%u", settings->deadzone[controller_page]); n64_virtualpak_write_string(buff, SUBHEADING + 7, MENU_EXT_FIELD); - sprintf(buff, "%u\0", settings->snap_axis[controller_page]); + sprintf(buff, "%u", settings->snap_axis[controller_page]); n64_virtualpak_write_string(buff, SUBHEADING + 10, MENU_EXT_FIELD); - sprintf(buff, "%u\0", settings->octa_correct[controller_page]); + sprintf(buff, "%u", settings->octa_correct[controller_page]); n64_virtualpak_write_string(buff, SUBHEADING + 11, MENU_EXT_FIELD); vpak->virtual_selected_row = -1; @@ -448,12 +448,12 @@ void n64_virtualpak_update(n64_mempack *vpak) void n64_virtualpak_write_info_1(char *msg) { - strncpy(info_text_0, msg, sizeof(info_text_0)); + strncpy(info_text_0, msg, sizeof(info_text_0) - 1); } void n64_virtualpak_write_info_2(char *msg) { - strncpy(info_text_1, msg, sizeof(info_text_1)); + strncpy(info_text_1, msg, sizeof(info_text_1) - 1); } uint8_t n64_virtualpak_get_controller_page() diff --git a/src/tft.cpp b/src/tft.cpp index 91ab673c..32913442 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -6,7 +6,6 @@ #include "n64_controller.h" #include "input.h" #include "memory.h" -#include "printf.h" #include "tft.h" #include "fileio.h" @@ -78,7 +77,7 @@ static const char *n64_peri_to_string(n64_input_dev_t *c) if (c->mempack->virtual_is_active) return "VIRTUAL PAK"; - snprintf(text_buff, sizeof(text_buff), "MPAK (BANK %lu)", c->mempack->id); + snprintf(text_buff, sizeof(text_buff), "MPAK (BANK %u)", c->mempack->id); return text_buff; case PERI_TPAK: snprintf(text_buff, sizeof(text_buff), "TPAK (%s)", (c->tpak->gbcart->rom == NULL) ? "NO ROM" : c->tpak->gbcart->title); @@ -127,7 +126,7 @@ void tft_try_update() //Dump the framebuffer to a file on the SD Card, 10 seconds after power up. Assuming 16bit display. //Convert to png with //ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb565le -s 320x240 -i tft_dump.bin -f image2 -vcodec png tft_dump.png - if (millis() > 10000) + if (n64hal_millis() > 10000) { fileio_write_to_file("tft_dump.bin", (uint8_t *)tft_dev_get_fb(), TFT_WIDTH * TFT_HEIGHT * 2); debug_print_status("TFT framebuffer dumped\n"); From 5586e20196b625ba703f6badb12127b5f33c7dbf Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 15:29:40 +1030 Subject: [PATCH 030/121] T4: Clean up includes --- src/teensy41/memory_t4.cpp | 1 - src/teensy41/tft_t4.cpp | 1 - src/teensy41/usbh_t4.cpp | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/teensy41/memory_t4.cpp b/src/teensy41/memory_t4.cpp index 9e25e3d1..c8fefa8d 100644 --- a/src/teensy41/memory_t4.cpp +++ b/src/teensy41/memory_t4.cpp @@ -3,7 +3,6 @@ #include #include "memory.h" -#include "printf.h" static uint32_t internal_size = 32768; //Smaller than this will malloc to internal RAM instead extern uint8_t external_psram_size; //in MB. Set in startup.c diff --git a/src/teensy41/tft_t4.cpp b/src/teensy41/tft_t4.cpp index 1591eeff..f5b909ce 100644 --- a/src/teensy41/tft_t4.cpp +++ b/src/teensy41/tft_t4.cpp @@ -5,7 +5,6 @@ #include "usb64_conf.h" #include "controller_icon.h" #include "usb64_logo.h" -#include "printf.h" #include "GuiLite.h" #if (ENABLE_TFT_DISPLAY >= 1) diff --git a/src/teensy41/usbh_t4.cpp b/src/teensy41/usbh_t4.cpp index 8a288609..fbc868bf 100644 --- a/src/teensy41/usbh_t4.cpp +++ b/src/teensy41/usbh_t4.cpp @@ -1,9 +1,8 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include +#include "usb64_conf.h" #include "tusb.h" -#include "printf.h" void USB_OTG2_IRQHandler(void) { From c739ec13d737c87f266fb88936d7d07281db99a2 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 15:30:40 +1030 Subject: [PATCH 031/121] usb64: Add null device --- platformio.ini | 16 ++- src/null/fileio_null.cpp | 40 +++++++ src/null/hal_null.cpp | 245 +++++++++++++++++++++++++++++++++++++++ src/null/memory_null.cpp | 24 ++++ src/null/tft_null.cpp | 58 +++++++++ src/null/usbh_null.cpp | 16 +++ 6 files changed, 398 insertions(+), 1 deletion(-) create mode 100644 src/null/fileio_null.cpp create mode 100644 src/null/hal_null.cpp create mode 100644 src/null/memory_null.cpp create mode 100644 src/null/tft_null.cpp create mode 100644 src/null/usbh_null.cpp diff --git a/platformio.ini b/platformio.ini index 7e7fca87..5c033662 100644 --- a/platformio.ini +++ b/platformio.ini @@ -25,6 +25,7 @@ src_filter = +<*.cpp> +<*.c> + + + + + @@ -63,7 +64,6 @@ src_filter = + + ;TinyUSB (T4 specific) - + + + + @@ -80,3 +80,17 @@ build_flags = -DCPU_MIMXRT1062DVL6A -DCFG_TUSB_MCU=OPT_MCU_MIMXRT10XX -DMCU_VARIANT=MIMXRT1062 + +[env:null] +platform = native + +src_filter = + ${common_env_data.src_filter} + + + + + + + +build_flags = + ${common_env_data.build_flags} + -Isrc/null/ + -DCFG_TUSB_MCU=OPT_MCU_NONE diff --git a/src/null/fileio_null.cpp b/src/null/fileio_null.cpp new file mode 100644 index 00000000..fd3798cd --- /dev/null +++ b/src/null/fileio_null.cpp @@ -0,0 +1,40 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include + +bool fileio_dev_init() +{ + return true; +} + +int fileio_dev_open_dir(const char *dir) +{ + return 0; +} + +const char *fileio_dev_get_next_filename(int handle) +{ + return NULL; +} + +void fileio_dev_close_dir(int handle) +{ +} + +//-1 Cant open +//-2 Cant read +//0 OK +int fileio_dev_read(char *filename, uint32_t file_offset, uint8_t *data, uint32_t len) +{ + return -1; +} + +//-1 Cant open +//-2 Cant read +//0 OK +int fileio_dev_write(char *filename, uint8_t *data, uint32_t len) +{ + return -1; +} diff --git a/src/null/hal_null.cpp b/src/null/hal_null.cpp new file mode 100644 index 00000000..2e8d3bc7 --- /dev/null +++ b/src/null/hal_null.cpp @@ -0,0 +1,245 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include "n64_controller.h" +#include "n64_wrapper.h" +#include "memory.h" +#include "usb64_conf.h" +#include "fileio.h" +#include "memory.h" + +void n64hal_system_init() +{ +} + +void n64hal_debug_init() +{ +} + +void n64hal_debug_write(char c) +{ +} + +void n64hal_disable_interrupts() +{ +} + +void n64hal_enable_interrupts() +{ +} + +/* + * Function: Reads a hardware realtime clock and populates day,h,m,s. + * Used by Pokemon Gameboy games only with TPAK that have a RTC. + * ---------------------------- + * Returns void + * + * day_high: Bit 0 Most significant bit of Day Counter (Bit 8) + * Bit 6 Halt (0=Active, 1=Stop Timer) + * Bit 7 Day Counter Carry Bit (1=Counter Overflow) + * day_low: Lower 8 bits of Day Counter (0-255) + * h: Pointer to an hour value (0-23) + * m: Pointer to a minute value (0-59) + * s: Pointer to a second value (0-59) + */ +void n64hal_rtc_read(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s) +{ + //Not implemented +} + +/* + * Function: Writes to a hardware realtime clock with day,h,m,s,dst + * Used by Pokemon Gameboy games only with TPAK that have a RTC. + * ---------------------------- + * Returns void + * + * day_high: Bit 0 Most significant bit of Day Counter (Bit 8) + * Bit 6 Halt (0=Active, 1=Stop Timer) + * Bit 7 Day Counter Carry Bit (1=Counter Overflow) + * day_low: Lower 8 bits of Day Counter (0-255) + * h: Pointer to an hour value (0-23) + * m: Pointer to a minute value (0-59) + * s: Pointer to a second value (0-59) + */ +void n64hal_rtc_write(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s) +{ + //Not implemented +} + +/* + * Function: Enable a high speed clock (>20Mhz or so) which is used for low level accurate timings. + * Timer range should be atleast 32-bit. + * Not speed critical + * ---------------------------- + * Returns: Void + */ +void n64hal_hs_tick_init() +{ +} + +/* + * Function: Returns to clock rate of the high speed clock in Hz. + * Speed critical! + * ---------------------------- + * Returns: The rate of the high speed clock in Hz + */ +uint32_t n64hal_hs_tick_get_speed() +{ + return 0; +} + +/* + * Function: Get the current value of the high speed clock. + * Speed critical! + * ---------------------------- + * Returns: A timer count that should run fairly fast (>20Mhz or so) + */ +uint32_t n64hal_hs_tick_get() +{ + return 0; +} + +/* + * Function: Flips the gpio pin direction from an output (driven low) to an input (pulled up) + * for the controller passed by controller. + * Speed critical! + * ---------------------------- + * Returns: void + * + * controller: Pointer to the n64 controller struct which contains the gpio mapping + * val: N64_OUTPUT or N64_INPUT + */ +void n64hal_input_swap(n64_input_dev_t *controller, uint8_t val) +{ +} + +/* + * Function: Returns the data line level for the pin passed to this function. + * Speed critical! + * ---------------------------- + * Returns: 1 of the line if high, or 0 if the line is low. + * + * Pin number: (See usb64_conf.h) + */ +uint8_t n64hal_input_read(int pin) +{ + return 0; +} + +/* + * Function: Sets the GPIO mode of a pin + * ---------------------------- + * Returns: void + * + * Pin number (See usb64_conf.h) + * val: N64_OUTPUT or N64_INPUT_PULLDOWN or N64_INPUT_PULLUP + */ +void n64hal_pin_set_mode(int pin, uint8_t mode) +{ +} + +/* + * Function: Sets an output GPI to a level + * Speed critical! + * ---------------------------- + * Returns: void. + * + * pin: Arduino compatible pin number + * level: 1 or 0 + */ +void n64hal_output_set(uint8_t pin, uint8_t level) +{ +} + +void n64hal_attach_interrupt(uint8_t pin, void (*handler)(void), int mode) +{ +} + +void n64hal_detach_interrupt(uint8_t pin) +{ +} + +/* + * Function: Returns an array of data read from external ram. + * ---------------------------- + * Returns: void + * + * rx_buff: The buffer the returned data will be stored + * src: Pointer to the base address of the source data. + * offset: Bytes from the base address the actual data is we need. + * len: How many bytes to read. + */ +void n64hal_read_extram(void *rx_buff, void *src, uint32_t offset, uint32_t len) +{ + memcpy(rx_buff, (void *)((uintptr_t)src + offset), len); +} + +/* + * Function: Writes an array of data read to external ram. + * ---------------------------- + * Returns: void + * + * tx_buff: The buffer of data to write + * dst: Pointer to the base address of the destination data. + * offset: Bytes from the base address where we need to write. + * len: How many bytes to write. + */ +void n64hal_write_extram(void *tx_buff, void *dst, uint32_t offset, uint32_t len) +{ + memcpy((void *)((uintptr_t)dst + offset), tx_buff, len); + memory_mark_dirty(dst); +} + +/* + * Function: Returns a list of gameboy roms located on nonvolatile storage + * WARNING: This mallocs memory on the heap. It must be free'd by user. + * ---------------------------- + * Returns: Number of roms found + * + * gb_list: A list of char pointers to populate + * max: Max number of roms to return + */ +uint32_t n64hal_list_gb_roms(char **gb_list, uint32_t max) +{ + //Retrieve full directory list + char *file_list[256]; + uint32_t num_files = fileio_list_directory(file_list, 256); + + //Find only files with .gb or gbc extensions to populate rom list. + uint32_t rom_count = 0; + for (uint32_t i = 0; i < num_files; i++) + { + if (file_list[i] == NULL) + continue; + + if (strstr(file_list[i], ".GB\0") != NULL || strstr(file_list[i], ".GBC\0") != NULL || + strstr(file_list[i], ".gb\0") != NULL || strstr(file_list[i], ".gbc\0") != NULL) + { + if (rom_count < max) + { + gb_list[rom_count] = (char *)memory_dev_malloc(strlen(file_list[i]) + 1); + strcpy(gb_list[rom_count], file_list[i]); + rom_count++; + } + } + //Free file list as we go + memory_dev_free(file_list[i]); + } + return rom_count; +} + +/* + * Function: Reads data from unbuffered memory. (i.e SD card) + * ---------------------------- + * Returns: Number of roms found + * + * name: Name of file + * file_offset: Located to start reading file + * data: buffer to put data in + * len: number of bytes t0 read. + */ +void n64hal_read_storage(char *name, uint32_t file_offset, uint8_t *data, uint32_t len) +{ + fileio_read_from_file(name, file_offset, data, len); +} diff --git a/src/null/memory_null.cpp b/src/null/memory_null.cpp new file mode 100644 index 00000000..a4833513 --- /dev/null +++ b/src/null/memory_null.cpp @@ -0,0 +1,24 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include "memory.h" + +bool memory_dev_init() +{ + return false; +} + +void *memory_dev_malloc(uint32_t len) +{ + return NULL; +} + +void memory_dev_free(void *add) +{ +} + +uint8_t memory_get_ext_ram_size() +{ + return 0; +} diff --git a/src/null/tft_null.cpp b/src/null/tft_null.cpp new file mode 100644 index 00000000..2fbb4ccb --- /dev/null +++ b/src/null/tft_null.cpp @@ -0,0 +1,58 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include "usb64_conf.h" +#include "controller_icon.h" +#include "usb64_logo.h" +#include "GuiLite.h" + +struct EXTERNAL_GFX_OP null_gfx_op; + +static void _draw_pixel(int x, int y, unsigned int rgb) +{ + //Device specific pixel draw +} + +static void _fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) +{ + //Device specific rect fill +} + +void tft_dev_draw(bool force) +{ + //Device specific draw start. This may be start DMA etc. +} + +static void _tft_assert(const char *file, int line) +{ + debug_print_error("[TFT] Error: Assert in %s on line %d\n", file, line); + while (1); +} + +static void _tft_log_out(const char *log) +{ + debug_print_status(log); +} + +void tft_dev_init() +{ + null_gfx_op.draw_pixel = _draw_pixel; + null_gfx_op.fill_rect = _fill_rect; +#if (ENABLE_TFT_DISPLAY >= 1) + //Device specific init here +#endif + register_debug_function(_tft_assert, _tft_log_out); +} + +void *tft_dev_get_fb() +{ + return NULL; +} + +bool tft_dev_is_busy() +{ +#if (ENABLE_TFT_DISPLAY >= 1) + return 0; +#endif +} diff --git a/src/null/usbh_null.cpp b/src/null/usbh_null.cpp new file mode 100644 index 00000000..582e8539 --- /dev/null +++ b/src/null/usbh_null.cpp @@ -0,0 +1,16 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include "tusb.h" + +void USB_IRQHandler(void) +{ + tuh_int_handler(0); +} + +void usbh_dev_init() +{ + //Device specific usb host hardware init. + //Look here for some rough guidance https://github.com/hathach/tinyusb/tree/master/hw/bsp + //Normally need to init hardware registers and USB clocks and hook the device USB IRQ to `USB_IRQHandler`. +} From 8e810cc9793de49f3ee1694cbacd2c3a494e94d7 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 15:32:36 +1030 Subject: [PATCH 032/121] TinyUSB: Update submodule --- src/lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tinyusb b/src/lib/tinyusb index 7a019582..1efdc168 160000 --- a/src/lib/tinyusb +++ b/src/lib/tinyusb @@ -1 +1 @@ -Subproject commit 7a0195828aee4cce473fc84cb0ba132c9f0bd64d +Subproject commit 1efdc16816f001657944c5349507eb46d1fa0270 From 3215f86245aa069f204ed3e31c807aa9da86e4fa Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 15:50:20 +1030 Subject: [PATCH 033/121] n64: Use my own sprintf --- src/n64/n64_virtualpak.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/n64/n64_virtualpak.c b/src/n64/n64_virtualpak.c index e8da29e0..25807acf 100644 --- a/src/n64/n64_virtualpak.c +++ b/src/n64/n64_virtualpak.c @@ -290,7 +290,7 @@ void n64_virtualpak_update(n64_mempack *vpak) //Print generic headers and footers n64_virtualpak_write_string("USB64 - RYZEE119", HEADING, MENU_NAME_FIELD); - sprintf(buff, "CONTROLLER %u", controller_page + 1); + sprintf_(buff, "CONTROLLER %u", controller_page + 1); n64_virtualpak_write_string(buff, SUBHEADING, MENU_NAME_FIELD); n64_virtualpak_write_string("________________", SUBHEADING + 1, MENU_NAME_FIELD); n64_virtualpak_write_string("CHANGE CONT", CHANGE_CONTROLLER, MENU_NAME_FIELD); @@ -353,7 +353,7 @@ void n64_virtualpak_update(n64_mempack *vpak) if (current_menu == MENU_CONTROLLER_SETTINGS) { - sprintf(buff, "CONTROLLER %u", controller_page + 1); + sprintf_(buff, "CONTROLLER %u", controller_page + 1); n64_virtualpak_write_string(buff, SUBHEADING + 0, MENU_NAME_FIELD); n64_virtualpak_write_string("________________", SUBHEADING + 1, MENU_NAME_FIELD); n64_virtualpak_write_string("CONT SETTINGS", SUBHEADING + 2, MENU_NAME_FIELD); @@ -396,16 +396,16 @@ void n64_virtualpak_update(n64_mempack *vpak) } //Print the current values of each setting - sprintf(buff, "%u", settings->sensitivity[controller_page]); + sprintf_(buff, "%u", settings->sensitivity[controller_page]); n64_virtualpak_write_string(buff, SUBHEADING + 4, MENU_EXT_FIELD); - sprintf(buff, "%u", settings->deadzone[controller_page]); + sprintf_(buff, "%u", settings->deadzone[controller_page]); n64_virtualpak_write_string(buff, SUBHEADING + 7, MENU_EXT_FIELD); - sprintf(buff, "%u", settings->snap_axis[controller_page]); + sprintf_(buff, "%u", settings->snap_axis[controller_page]); n64_virtualpak_write_string(buff, SUBHEADING + 10, MENU_EXT_FIELD); - sprintf(buff, "%u", settings->octa_correct[controller_page]); + sprintf_(buff, "%u", settings->octa_correct[controller_page]); n64_virtualpak_write_string(buff, SUBHEADING + 11, MENU_EXT_FIELD); vpak->virtual_selected_row = -1; From 2e5f0d56c4297cdf80af7db62144ee6641a0562d Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 16:00:30 +1030 Subject: [PATCH 034/121] USBH: Add HID driver stub --- src/lib/hid_host.c | 36 ++++++++++++++++++++++++++++++++++++ src/lib/hid_host.h | 15 +++++++++++++++ src/lib/tusb_config.h | 2 +- 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/lib/hid_host.c create mode 100644 src/lib/hid_host.h diff --git a/src/lib/hid_host.c b/src/lib/hid_host.c new file mode 100644 index 00000000..5417c721 --- /dev/null +++ b/src/lib/hid_host.c @@ -0,0 +1,36 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include "tusb_option.h" + +#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) + +#include "host/usbh.h" +#include "host/usbh_classdriver.h" +#include "hid_host.h" + +// Invoked when device with hid interface is mounted +// Report descriptor is also available for use. tuh_hid_parse_report_descriptor() +// can be used to parse common/simple enough descriptor. +// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped +// therefore report_desc = NULL, desc_len = 0 +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) +{ + uint16_t vid, pid; + tuh_vid_pid_get(dev_addr, &vid, &pid); + + TU_LOG2("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance); + TU_LOG2("VID = %04x, PID = %04x\r\n", vid, pid); +} + +// Invoked when received report from device via interrupt endpoint +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) +{ + // continue to request to receive report + if ( !tuh_hid_receive_report(dev_addr, instance) ) + { + TU_LOG2("Error: cannot request to receive report\r\n"); + } +} + +#endif \ No newline at end of file diff --git a/src/lib/hid_host.h b/src/lib/hid_host.h new file mode 100644 index 00000000..c03224dc --- /dev/null +++ b/src/lib/hid_host.h @@ -0,0 +1,15 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#ifndef _TUSB_XINPUT_HOST_H_ +#define _TUSB_XINPUT_HOST_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_XINPUT_HOST_H_ */ \ No newline at end of file diff --git a/src/lib/tusb_config.h b/src/lib/tusb_config.h index ea65d7ae..a2edfc2c 100644 --- a/src/lib/tusb_config.h +++ b/src/lib/tusb_config.h @@ -76,7 +76,7 @@ #define CFG_TUH_HUB 1 #define CFG_TUH_CDC 0 -#define CFG_TUH_HID 0 // typical keyboard + mouse device can have 3-4 HID interfaces +#define CFG_TUH_HID 4 // typical keyboard + mouse device can have 3-4 HID interfaces #define CFG_TUH_MSC 0 #define CFG_TUH_VENDOR 0 #define CFG_TUH_XINPUT 4 From a578c3bdd5e86c15fc3023b873d7a6f50dc70793 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 16:00:51 +1030 Subject: [PATCH 035/121] Xinput: Format driver --- src/lib/xinput_host.h | 35 ++++++----------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/src/lib/xinput_host.h b/src/lib/xinput_host.h index 804ebac3..64ed7d0e 100644 --- a/src/lib/xinput_host.h +++ b/src/lib/xinput_host.h @@ -1,31 +1,8 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#ifndef _TUSB_xinput_HOST_H_ -#define _TUSB_xinput_HOST_H_ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#ifndef _TUSB_XINPUT_HOST_H_ +#define _TUSB_XINPUT_HOST_H_ #ifdef __cplusplus extern "C" { @@ -146,4 +123,4 @@ static const uint8_t xboxog_rumble[] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00}; } #endif -#endif /* _TUSB_xinput_HOST_H_ */ +#endif /* _TUSB_XINPUT_HOST_H_ */ From 095738711d832334bb25361e590aa282bcec54f8 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 16:02:51 +1030 Subject: [PATCH 036/121] usb64: Rename port folders --- .gitmodules | 2 +- platformio.ini | 18 +++++++++--------- src/{null => port_null}/fileio_null.cpp | 0 src/{null => port_null}/hal_null.cpp | 0 src/{null => port_null}/memory_null.cpp | 0 src/{null => port_null}/tft_null.cpp | 0 src/{null => port_null}/usbh_null.cpp | 0 src/{teensy41 => port_teensy41}/ILI9341_t3n | 0 src/{teensy41 => port_teensy41}/fileio_t4.cpp | 0 src/{teensy41 => port_teensy41}/hal_t4.cpp | 0 src/{teensy41 => port_teensy41}/memory_t4.cpp | 0 src/{teensy41 => port_teensy41}/tft_t4.cpp | 0 src/{teensy41 => port_teensy41}/usbh_t4.cpp | 0 13 files changed, 10 insertions(+), 10 deletions(-) rename src/{null => port_null}/fileio_null.cpp (100%) rename src/{null => port_null}/hal_null.cpp (100%) rename src/{null => port_null}/memory_null.cpp (100%) rename src/{null => port_null}/tft_null.cpp (100%) rename src/{null => port_null}/usbh_null.cpp (100%) rename src/{teensy41 => port_teensy41}/ILI9341_t3n (100%) rename src/{teensy41 => port_teensy41}/fileio_t4.cpp (100%) rename src/{teensy41 => port_teensy41}/hal_t4.cpp (100%) rename src/{teensy41 => port_teensy41}/memory_t4.cpp (100%) rename src/{teensy41 => port_teensy41}/tft_t4.cpp (100%) rename src/{teensy41 => port_teensy41}/usbh_t4.cpp (100%) diff --git a/.gitmodules b/.gitmodules index 849b0eff..fceed2be 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,5 +6,5 @@ path = src/lib/tinyusb url = https://github.com/hathach/tinyusb.git [submodule "src/teensy41/ILI9341_t3n"] - path = src/teensy41/ILI9341_t3n + path = src/port_teensy41/ILI9341_t3n url = https://github.com/KurtE/ILI9341_t3n.git diff --git a/platformio.ini b/platformio.ini index 5c033662..57954415 100644 --- a/platformio.ini +++ b/platformio.ini @@ -59,10 +59,10 @@ framework = arduino src_filter = ${common_env_data.src_filter} - + - + - + - + + + + + + + + + ;TinyUSB (T4 specific) + + @@ -70,8 +70,8 @@ src_filter = build_flags = ${common_env_data.build_flags} - -Isrc/teensy41/ - -Isrc/teensy41/ILI9341_t3n/src + -Isrc/port_teensy41/ + -Isrc/port_teensy41/ILI9341_t3n/src ;TinyUSB (T4 specific) -Isrc/lib/tinyusb/hw/mcu/nxp/mcux-sdk/CMSIS/Include -Isrc/lib/tinyusb/hw/mcu/nxp/mcux-sdk/devices/MIMXRT1062 @@ -86,11 +86,11 @@ platform = native src_filter = ${common_env_data.src_filter} - + - + + + + + + build_flags = ${common_env_data.build_flags} - -Isrc/null/ + -Isrc/port_null/ -DCFG_TUSB_MCU=OPT_MCU_NONE diff --git a/src/null/fileio_null.cpp b/src/port_null/fileio_null.cpp similarity index 100% rename from src/null/fileio_null.cpp rename to src/port_null/fileio_null.cpp diff --git a/src/null/hal_null.cpp b/src/port_null/hal_null.cpp similarity index 100% rename from src/null/hal_null.cpp rename to src/port_null/hal_null.cpp diff --git a/src/null/memory_null.cpp b/src/port_null/memory_null.cpp similarity index 100% rename from src/null/memory_null.cpp rename to src/port_null/memory_null.cpp diff --git a/src/null/tft_null.cpp b/src/port_null/tft_null.cpp similarity index 100% rename from src/null/tft_null.cpp rename to src/port_null/tft_null.cpp diff --git a/src/null/usbh_null.cpp b/src/port_null/usbh_null.cpp similarity index 100% rename from src/null/usbh_null.cpp rename to src/port_null/usbh_null.cpp diff --git a/src/teensy41/ILI9341_t3n b/src/port_teensy41/ILI9341_t3n similarity index 100% rename from src/teensy41/ILI9341_t3n rename to src/port_teensy41/ILI9341_t3n diff --git a/src/teensy41/fileio_t4.cpp b/src/port_teensy41/fileio_t4.cpp similarity index 100% rename from src/teensy41/fileio_t4.cpp rename to src/port_teensy41/fileio_t4.cpp diff --git a/src/teensy41/hal_t4.cpp b/src/port_teensy41/hal_t4.cpp similarity index 100% rename from src/teensy41/hal_t4.cpp rename to src/port_teensy41/hal_t4.cpp diff --git a/src/teensy41/memory_t4.cpp b/src/port_teensy41/memory_t4.cpp similarity index 100% rename from src/teensy41/memory_t4.cpp rename to src/port_teensy41/memory_t4.cpp diff --git a/src/teensy41/tft_t4.cpp b/src/port_teensy41/tft_t4.cpp similarity index 100% rename from src/teensy41/tft_t4.cpp rename to src/port_teensy41/tft_t4.cpp diff --git a/src/teensy41/usbh_t4.cpp b/src/port_teensy41/usbh_t4.cpp similarity index 100% rename from src/teensy41/usbh_t4.cpp rename to src/port_teensy41/usbh_t4.cpp From 95d8a85786b83c130a16e491ae8fd34a6809b995 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 16:07:49 +1030 Subject: [PATCH 037/121] Build: build all environments --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a01499c0..05a6b26b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,7 +43,7 @@ jobs: echo "BUILD_TAG=$BUILD_TAG" >> $GITHUB_ENV - name: Compile code - run: platformio run -e teensy41 + run: platformio run - if: github.event_name == 'push' name: Create Release From b9505580bbd9367af4d0352c0d8d0eed81dc9e58 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 16:13:00 +1030 Subject: [PATCH 038/121] HID: Use inbuilt hid header --- src/lib/hid_host.c | 2 +- src/lib/hid_host.h | 15 --------------- 2 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 src/lib/hid_host.h diff --git a/src/lib/hid_host.c b/src/lib/hid_host.c index 5417c721..01e0fd79 100644 --- a/src/lib/hid_host.c +++ b/src/lib/hid_host.c @@ -7,7 +7,7 @@ #include "host/usbh.h" #include "host/usbh_classdriver.h" -#include "hid_host.h" +#include "class/hid/hid_host.h" // Invoked when device with hid interface is mounted // Report descriptor is also available for use. tuh_hid_parse_report_descriptor() diff --git a/src/lib/hid_host.h b/src/lib/hid_host.h deleted file mode 100644 index c03224dc..00000000 --- a/src/lib/hid_host.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#ifndef _TUSB_XINPUT_HOST_H_ -#define _TUSB_XINPUT_HOST_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* _TUSB_XINPUT_HOST_H_ */ \ No newline at end of file From fadbb2ee6f4d96084a31b8c3aeae7e83810b955e Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 18:09:21 +1030 Subject: [PATCH 039/121] TFT: Rework and allow use with no framebuffer --- src/port_null/tft_null.cpp | 92 +++++++++++++++++++++------- src/port_teensy41/tft_t4.cpp | 113 ++++++++++++++++++++++------------- src/tft.cpp | 43 +++++++------ src/tft.h | 1 - src/usb64_conf.h | 16 ++--- 5 files changed, 172 insertions(+), 93 deletions(-) diff --git a/src/port_null/tft_null.cpp b/src/port_null/tft_null.cpp index 2fbb4ccb..fb7d60e0 100644 --- a/src/port_null/tft_null.cpp +++ b/src/port_null/tft_null.cpp @@ -7,52 +7,100 @@ #include "usb64_logo.h" #include "GuiLite.h" -struct EXTERNAL_GFX_OP null_gfx_op; +c_surface *psurface_guilite = NULL; +c_display *pdisplay_guilite = NULL; +#if TFT_USE_FRAMEBUFFER +static uint8_t _framebuffer[TFT_WIDTH * TFT_HEIGHT * TFT_PIXEL_SIZE]; +#else +struct EXTERNAL_GFX_OP my_gfx_op; +#endif -static void _draw_pixel(int x, int y, unsigned int rgb) +//Stub for GuiLite. Remove if not required. +extern "C" void delay_ms(unsigned short nms) { - //Device specific pixel draw } -static void _fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) +static void _tft_assert(const char *file, int line) { - //Device specific rect fill + debug_print_error("[TFT] Error: Assert in %s on line %d\n", file, line); + while (1) + ; } -void tft_dev_draw(bool force) +static void _tft_log_out(const char *log) { - //Device specific draw start. This may be start DMA etc. + debug_print_status(log); } -static void _tft_assert(const char *file, int line) +#if TFT_USE_FRAMEBUFFER == 0 +/* + * Function: Draw a pixel to your display at a given coordinate. Required if NOT using a framebuffer + * ---------------------------- + * Returns: Void + * + * x: horizontal pixel position + * y: vertical pixel position + * rgb: RGB888 colour. You can use GL_RGB_32_to_16 to convert to RGB565 if needed. + */ +static void _draw_pixel(int x, int y, unsigned int rgb) { - debug_print_error("[TFT] Error: Assert in %s on line %d\n", file, line); - while (1); + //Device specific pixel draw } -static void _tft_log_out(const char *log) +/* + * Function: Fill a given rectangle area. Required if NOT using a framebuffer + * ---------------------------- + * Returns: Void + * + * x0,y0: Top left rectangle pixel position + * x1,y1: Bottom right pixel position + * rgb: RGB888 colour. You can use GL_RGB_32_to_16 to convert to RGB565 if needed. + */ +static void _fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) { - debug_print_status(log); + +} +#endif + +/* + * Function: Start TFT draw. Required if using a framebuffer. This should draw the framebuffer to the screen using DMA or similar. + * ---------------------------- + * Returns: Void + * + * force: If force is true, you must wait for any previous screen updates to finished then update. + */ +void tft_dev_draw(bool force) +{ + //Draw _framebuffer to screen if TFT_USE_FRAMEBUFFER is set. } +/* + * Function: Perform any device specific LCD display setup here. + * ---------------------------- + * Returns: Void + */ void tft_dev_init() { - null_gfx_op.draw_pixel = _draw_pixel; - null_gfx_op.fill_rect = _fill_rect; +#if TFT_USE_FRAMEBUFFER + static c_surface surface(TFT_WIDTH, TFT_HEIGHT, 2, Z_ORDER_LEVEL_0); + static c_display display(_framebuffer, TFT_WIDTH, TFT_HEIGHT, &surface); + psurface_guilite = &surface; + pdisplay_guilite = &display; +#else + static c_surface_no_fb surface(TFT_WIDTH, TFT_HEIGHT, 2, &my_gfx_op, Z_ORDER_LEVEL_0); + static c_display display(NULL, TFT_WIDTH, TFT_HEIGHT, &surface); + my_gfx_op.draw_pixel = _draw_pixel; + my_gfx_op.fill_rect = _fill_rect; +#endif + psurface_guilite = &surface; + pdisplay_guilite = &display; + register_debug_function(_tft_assert, _tft_log_out); #if (ENABLE_TFT_DISPLAY >= 1) //Device specific init here #endif - register_debug_function(_tft_assert, _tft_log_out); -} - -void *tft_dev_get_fb() -{ - return NULL; } bool tft_dev_is_busy() { -#if (ENABLE_TFT_DISPLAY >= 1) return 0; -#endif } diff --git a/src/port_teensy41/tft_t4.cpp b/src/port_teensy41/tft_t4.cpp index f5b909ce..3c08509a 100644 --- a/src/port_teensy41/tft_t4.cpp +++ b/src/port_teensy41/tft_t4.cpp @@ -7,79 +7,110 @@ #include "usb64_logo.h" #include "GuiLite.h" -#if (ENABLE_TFT_DISPLAY >= 1) -#include "ILI9341_t3n.h" -static ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO); -static DMAMEM uint16_t _framebuffer[320 * 240]; +c_surface *psurface_guilite = NULL; +c_display *pdisplay_guilite = NULL; +#if TFT_USE_FRAMEBUFFER +static DMAMEM uint8_t _framebuffer[TFT_WIDTH * TFT_HEIGHT * TFT_PIXEL_SIZE]; #else -//Stub a framebuffer -static uint16_t _framebuffer[1]; +struct EXTERNAL_GFX_OP my_gfx_op; #endif -struct EXTERNAL_GFX_OP t4_gfx_op; +#include "ILI9341_t3n.h" +static ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO); + +static void _tft_assert(const char *file, int line) +{ + debug_print_error("[TFT] Error: Assert in %s on line %d\n", file, line); + while (1) + ; +} +static void _tft_log_out(const char *log) +{ + debug_print_status(log); +} + +#if TFT_USE_FRAMEBUFFER == 0 +/* + * Function: Draw a pixel to your display at a given coordinate. Required if NOT using a framebuffer + * ---------------------------- + * Returns: Void + * + * x: horizontal pixel position + * y: vertical pixel position + * rgb: RGB888 colour. You can use GL_RGB_32_to_16 to convert to RGB565 if needed. + */ static void _draw_pixel(int x, int y, unsigned int rgb) { -#if (ENABLE_TFT_DISPLAY >= 1) tft.drawPixel(x, y, GL_RGB_32_to_16(rgb)); -#endif } +/* + * Function: Fill a given rectangle area. Required if NOT using a framebuffer + * ---------------------------- + * Returns: Void + * + * x0,y0: Top left rectangle pixel position + * x1,y1: Bottom right pixel position + * rgb: RGB888 colour. You can use GL_RGB_32_to_16 to convert to RGB565 if needed. + */ static void _fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) { -#if (ENABLE_TFT_DISPLAY >= 1) tft.fillRect(x0, y0, x1 - x0, y1 - y0, GL_RGB_32_to_16(rgb)); -#endif } +#endif +/* + * Function: Start TFT draw. Required if using a framebuffer. This should draw the framebuffer to the screen using DMA or similar. + * ---------------------------- + * Returns: Void + * + * force: If force is true, you must wait for any previous screen updates to finished then update. + */ void tft_dev_draw(bool force) { -#if (ENABLE_TFT_DISPLAY >= 1) - if (!force && tft.asyncUpdateActive()) +#if TFT_USE_FRAMEBUFFER + if (force) + { + while (tft.asyncUpdateActive()); + tft.updateScreenAsync(); + } + else if (tft.asyncUpdateActive()) { return; } - while (tft.asyncUpdateActive()) - ; - tft.updateScreenAsync(); -#endif -} - -static void _tft_assert(const char *file, int line) -{ - debug_print_error("[TFT] Error: Assert in %s on line %d\n", file, line); - while (1) - yield(); -} -static void _tft_log_out(const char *log) -{ - debug_print_status(log); +#endif } +/* + * Function: Perform any device specific LCD display setup here. + * ---------------------------- + * Returns: Void + */ void tft_dev_init() { - t4_gfx_op.draw_pixel = _draw_pixel; - t4_gfx_op.fill_rect = _fill_rect; - -#if (ENABLE_TFT_DISPLAY >= 1) tft.begin(); tft.setRotation(TFT_ROTATION); - tft.setFrameBuffer(_framebuffer); +#if TFT_USE_FRAMEBUFFER + static c_surface surface(TFT_WIDTH, TFT_HEIGHT, 2, Z_ORDER_LEVEL_0); + static c_display display(_framebuffer, TFT_WIDTH, TFT_HEIGHT, &surface); + psurface_guilite = &surface; + pdisplay_guilite = &display; + tft.setFrameBuffer((uint16_t *)_framebuffer); tft.useFrameBuffer(true); +#else + static c_surface_no_fb surface(TFT_WIDTH, TFT_HEIGHT, 2, &my_gfx_op, Z_ORDER_LEVEL_0); + static c_display display(NULL, TFT_WIDTH, TFT_HEIGHT, &surface); + my_gfx_op.draw_pixel = _draw_pixel; + my_gfx_op.fill_rect = _fill_rect; #endif - + psurface_guilite = &surface; + pdisplay_guilite = &display; register_debug_function(_tft_assert, _tft_log_out); } -void *tft_dev_get_fb() -{ - return _framebuffer; -} - bool tft_dev_is_busy() { -#if (ENABLE_TFT_DISPLAY >= 1) return tft.asyncUpdateActive(); -#endif } diff --git a/src/tft.cpp b/src/tft.cpp index 32913442..e452804d 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -34,8 +34,7 @@ static char text_buff[32]; #define BG_COLOR GL_RGB(16, 20, 16) extern const LATTICE_FONT_INFO Arial_14_GL; extern const LATTICE_FONT_INFO Arial_19_GL; -static c_surface *psurface; -static c_display *pdisplay; +extern c_surface *psurface_guilite; static c_label n64_status; static c_label fileio_status; static c_label extram_size; @@ -91,12 +90,12 @@ void tft_init() { tft_dev_init(); - static c_surface surface(TFT_WIDTH, TFT_HEIGHT, 2, Z_ORDER_LEVEL_0); - static c_display display(tft_dev_get_fb(), TFT_WIDTH, TFT_HEIGHT, &surface); - psurface = &surface; - pdisplay = &display; - - surface.fill_rect(0, 0, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); + if (psurface_guilite == NULL) + { + return; + } + + psurface_guilite->fill_rect(0, 0, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); static c_image usb64_image; memset(&usb64_image, 0, sizeof(c_image)); @@ -105,11 +104,11 @@ void tft_init() _image.height = 35; _image.width = 120; _image.pixel_color_array = usb64_logo; - usb64_image.draw_image(psurface, Z_ORDER_LEVEL_0, &_image, 0, 0, BG_COLOR); + usb64_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 0, BG_COLOR); //Draw RAM status snprintf(text_buff, sizeof(text_buff), "Detected RAM: %uMB", memory_get_ext_ram_size()); - extram_size.set_surface(psurface); + extram_size.set_surface(psurface_guilite); extram_size.set_bg_color(BG_COLOR); extram_size.set_font_color(GL_RGB(255, 255, 255)); extram_size.set_wnd_pos(125, 0, 1, Arial_14_GL.height); @@ -162,7 +161,7 @@ void tft_force_update() _tft_page_changed = 0; if (_tft_page == 0) { - psurface->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); + psurface_guilite->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); static c_image controller_image; BITMAP_INFO _image; memset(&controller_image, 0, sizeof(c_image)); @@ -170,14 +169,14 @@ void tft_force_update() _image.height = 45; _image.width = 48; _image.pixel_color_array = controller_icon; - controller_image.draw_image(psurface, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 0 / 4), BG_COLOR); - controller_image.draw_image(psurface, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 1 / 4), BG_COLOR); - controller_image.draw_image(psurface, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 2 / 4), BG_COLOR); - controller_image.draw_image(psurface, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 3 / 4), BG_COLOR); + controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 0 / 4), BG_COLOR); + controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 1 / 4), BG_COLOR); + controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 2 / 4), BG_COLOR); + controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 3 / 4), BG_COLOR); } else if (_tft_page == 1) { - psurface->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); + psurface_guilite->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); } } @@ -188,7 +187,7 @@ void tft_force_update() for (int i = 0; i < 4; i++) { uint32_t colour = input_is_connected(i) ? GL_RGB(0, 255, 0) : GL_RGB(255, 255, 255); - controller_status[i].set_surface(psurface); + controller_status[i].set_surface(psurface_guilite); controller_status[i].set_bg_color(BG_COLOR); controller_status[i].set_font_color(colour); controller_status[i].set_wnd_pos(50, (45 + 0) + ((TFT_HEIGHT - 45) * i / 4), TFT_WIDTH, Arial_19_GL.height); @@ -197,7 +196,7 @@ void tft_force_update() controller_status[i].show_window(); snprintf(text_buff, sizeof(text_buff), "0x%04x/0x%04x", input_get_id_vendor(i), input_get_id_product(i)); - controller_id[i].set_surface(psurface); + controller_id[i].set_surface(psurface_guilite); controller_id[i].set_font_color(colour); controller_id[i].set_bg_color(BG_COLOR); controller_id[i].set_wnd_pos(50, (45 + 20) + ((TFT_HEIGHT - 45) * i / 4), TFT_WIDTH, Arial_19_GL.height); @@ -208,13 +207,13 @@ void tft_force_update() } else if (_tft_page == 1) { - psurface->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); + psurface_guilite->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); for (int i = 0; i < _tft_log_max_lines; i++) { if (_tft_log_text_lines[i] == NULL) break; - tft_log[i].set_surface(psurface); + tft_log[i].set_surface(psurface_guilite); tft_log[i].set_bg_color(BG_COLOR); tft_log[i].set_font_color(GL_RGB(255, 255, 255)); tft_log[i].set_wnd_pos(0, 45 + i * Arial_14_GL.height, TFT_WIDTH, Arial_14_GL.height); @@ -237,7 +236,7 @@ void tft_force_update() n64_status_text = "N64 is ON"; colour = GL_RGB(0, 255, 0); } - n64_status.set_surface(psurface); + n64_status.set_surface(psurface_guilite); n64_status.set_bg_color(BG_COLOR); n64_status.set_font_color(colour); n64_status.set_wnd_pos(TFT_WIDTH - (10 * 8), 0, 100, Arial_14_GL.height); @@ -257,7 +256,7 @@ void tft_force_update() fileio_status_text = "SD Detected"; colour = GL_RGB(0, 255, 0); } - n64_status.set_surface(psurface); + n64_status.set_surface(psurface_guilite); n64_status.set_bg_color(BG_COLOR); n64_status.set_font_color(colour); n64_status.set_wnd_pos(125, Arial_14_GL.height, 100, Arial_14_GL.height); diff --git a/src/tft.h b/src/tft.h index e9208b07..93ec0919 100644 --- a/src/tft.h +++ b/src/tft.h @@ -15,7 +15,6 @@ void tft_add_log(char c); //TFT device specific functions. void tft_dev_init(); void tft_dev_draw(bool force); -void *tft_dev_get_fb(); bool tft_dev_is_busy(); #endif \ No newline at end of file diff --git a/src/usb64_conf.h b/src/usb64_conf.h index 9c88c062..add67af9 100644 --- a/src/usb64_conf.h +++ b/src/usb64_conf.h @@ -100,6 +100,8 @@ #define TFT_RST 255 #define TFT_WIDTH 320 #define TFT_HEIGHT 240 +#define TFT_PIXEL_SIZE 2 +#define TFT_USE_FRAMEBUFFER 1 /* Define for variables to store in flash only */ #ifndef PROGMEM @@ -107,12 +109,12 @@ #endif /* DEBUG PRINTERS */ -#define debug_print_status(fmt, ...) do { if (DEBUG_STATUS) printf_(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_n64(fmt, ...) do { if (DEBUG_N64) printf_(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_tpak(fmt, ...) do { if (DEBUG_TPAK) printf_(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_usbhost(fmt, ...) do { if (DEBUG_USBHOST) printf_(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_fatfs(fmt, ...) do { if (DEBUG_FATFS) printf_(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_memory(fmt, ...) do { if (DEBUG_MEMORY) printf_(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_error(fmt, ...) do { if (DEBUG_ERROR) printf_(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_status(fmt, ...) do { if (DEBUG_STATUS) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_n64(fmt, ...) do { if (DEBUG_N64) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_tpak(fmt, ...) do { if (DEBUG_TPAK) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_usbhost(fmt, ...) do { if (DEBUG_USBHOST) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_fatfs(fmt, ...) do { if (DEBUG_FATFS) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_memory(fmt, ...) do { if (DEBUG_MEMORY) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_error(fmt, ...) do { if (DEBUG_ERROR) usb64_printf(fmt, ##__VA_ARGS__); } while (0) #endif \ No newline at end of file From 0045a892b5c784cc0a12e706373169b95d0ebf71 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 18:10:02 +1030 Subject: [PATCH 040/121] Null: Comment all functions for porting --- src/port_null/fileio_null.cpp | 50 +++++++++++++++++++++++---- src/port_null/hal_null.cpp | 63 +++++++++++++++++++++++++++++------ src/port_null/memory_null.cpp | 26 +++++++++++++++ 3 files changed, 122 insertions(+), 17 deletions(-) diff --git a/src/port_null/fileio_null.cpp b/src/port_null/fileio_null.cpp index fd3798cd..6bdee4fc 100644 --- a/src/port_null/fileio_null.cpp +++ b/src/port_null/fileio_null.cpp @@ -4,36 +4,74 @@ #include #include +/* + * Function: Initliased the File access device (SD Card, EMMC, Flash ROM, etc) + * This is used to save/load mempaks, usb64 config settings, GB Roms for transfer pak etc. + * ---------------------------- + * Returns true on sucess. + */ bool fileio_dev_init() { return true; } +/* + * Function: Opens a directory and returns a handle to it. + * Used in confunction with fileio_dev_get_next_filename()and fileio_dev_close_dir(); + * ---------------------------- + * dir: The directory path to open. "/" should be the root directory. + * Returns handle or 0 on error. + */ int fileio_dev_open_dir(const char *dir) { return 0; } +/* + * Function: Returns the next filename of a file in a directory handle from fileio_dev_open_dir. + * Used in confunction with fileio_dev_open_dir()and fileio_dev_close_dir(); + * ---------------------------- + * handle: The directory handle to get the next file from. + * Returns filename or NULL on error/no more files. + */ const char *fileio_dev_get_next_filename(int handle) { return NULL; } +/* + * Function: Closes a directory handle opened with fileio_dev_open_dir + * Used in confunction with fileio_dev_open_dir() and fileio_dev_get_next_filename(); + * ---------------------------- + * handle: The directory handle to close obtained with fileio_dev_open_dir + * Returns void. + */ void fileio_dev_close_dir(int handle) { } -//-1 Cant open -//-2 Cant read -//0 OK +/* + * Function: Reads a file from storage. + * ---------------------------- + * filename: The name of the file to read. + * file_offset: The offset of the file to read from. 0 is the beginning of the file. + * data: Return data buffer + * len: How many bytes to read from file_offset + * Returns -1: Cant open file, -2: Cant read file: 0: Success. + */ int fileio_dev_read(char *filename, uint32_t file_offset, uint8_t *data, uint32_t len) { return -1; } -//-1 Cant open -//-2 Cant read -//0 OK +/* + * Function: Writes a file to storage. This should always create a new file or overwrite if the file exists. + * ---------------------------- + * filename: The name of the file to write. + * data: The data to write + * len: How many bytes to write + * Returns -1: Cant open file, -2: Cant read file: 0: Success. + */ int fileio_dev_write(char *filename, uint8_t *data, uint32_t len) { return -1; diff --git a/src/port_null/hal_null.cpp b/src/port_null/hal_null.cpp index 2e8d3bc7..232bbb6e 100644 --- a/src/port_null/hal_null.cpp +++ b/src/port_null/hal_null.cpp @@ -9,26 +9,75 @@ #include "fileio.h" #include "memory.h" +/* + * Function: Initialse any device specifc aspects + * ---------------------------- + * Returns: void + */ void n64hal_system_init() { } +/* + * Function: Initialse the device debuffer (i.e UART etc) + * ---------------------------- + * Returns: void + */ void n64hal_debug_init() { } +/* + * Function: Write a character to a debug output (i.e UART etc) + * ---------------------------- + * Returns: void + */ void n64hal_debug_write(char c) { } +/* + * Function: Disable global interrupts for the device. + * ---------------------------- + * Returns: void + */ void n64hal_disable_interrupts() { } +/* + * Function: Enable global interrupts for the device. + * ---------------------------- + * Returns: void + */ void n64hal_enable_interrupts() { } +/* + * Function: Attach an interrupt from a pin (See usb64_conf.h for pin numbers) + * ---------------------------- + * Returns: void + * + * pin: The pin the configure (See usb64_conf.h) + * handler: Interrupt handler function in the form `void my_int_handler(void)` + * mode: N64_INTMODE_FALLING or N64_INTMODE_CHANGE or N64_INTMODE_RISING + */ +void n64hal_attach_interrupt(uint8_t pin, void (*handler)(void), int mode) +{ +} + +/* + * Function: Disconnect an interrupt from a pin (See usb64_conf.h for pin numbers) + * ---------------------------- + * Returns: void + * + * pin: The pin the configure (See usb64_conf.h) + */ +void n64hal_detach_interrupt(uint8_t pin) +{ +} + /* * Function: Reads a hardware realtime clock and populates day,h,m,s. * Used by Pokemon Gameboy games only with TPAK that have a RTC. @@ -120,7 +169,7 @@ void n64hal_input_swap(n64_input_dev_t *controller, uint8_t val) * ---------------------------- * Returns: 1 of the line if high, or 0 if the line is low. * - * Pin number: (See usb64_conf.h) + * pin: The pin the configure (See usb64_conf.h) */ uint8_t n64hal_input_read(int pin) { @@ -132,7 +181,7 @@ uint8_t n64hal_input_read(int pin) * ---------------------------- * Returns: void * - * Pin number (See usb64_conf.h) + * pin: The pin the configure (See usb64_conf.h) * val: N64_OUTPUT or N64_INPUT_PULLDOWN or N64_INPUT_PULLUP */ void n64hal_pin_set_mode(int pin, uint8_t mode) @@ -145,21 +194,13 @@ void n64hal_pin_set_mode(int pin, uint8_t mode) * ---------------------------- * Returns: void. * - * pin: Arduino compatible pin number + * pin: The pin the configure (See usb64_conf.h) * level: 1 or 0 */ void n64hal_output_set(uint8_t pin, uint8_t level) { } -void n64hal_attach_interrupt(uint8_t pin, void (*handler)(void), int mode) -{ -} - -void n64hal_detach_interrupt(uint8_t pin) -{ -} - /* * Function: Returns an array of data read from external ram. * ---------------------------- diff --git a/src/port_null/memory_null.cpp b/src/port_null/memory_null.cpp index a4833513..24400510 100644 --- a/src/port_null/memory_null.cpp +++ b/src/port_null/memory_null.cpp @@ -4,20 +4,46 @@ #include #include "memory.h" +/* + * Function: Initalise memory for device (External RAM etc) + * ---------------------------- + * Returns: true on success, false on error + */ bool memory_dev_init() { return false; } +/* + * Function: Allocate a block of memory. This could be large block if using TPAK emulation. + * This function should use internal or external RAM as required. Freed with memory_dev_free() + * ---------------------------- + * Returns: A pointer to the alloced memory, or NULL on error. + * + * len: How many bytes to allocate. + */ void *memory_dev_malloc(uint32_t len) { return NULL; } +/* + * Function: Free an allocated memory block allocated with memory_dev_malloc(); + * ---------------------------- + * Returns: Void + * + * add: Pointer to the address block to free + */ void memory_dev_free(void *add) { } +/* + * Function: Detect the amount of external RAM installed. This prints it to the LCD and a number > 0 is required for TPAK + * emulation. If you device has loads of internal RAM suitable for TPAK emulation (>2MB or so) which you want to use, set this to a non-zero number. + * ---------------------------- + * Returns: How many MB of external RAM is installed. + */ uint8_t memory_get_ext_ram_size() { return 0; From 6abe568d0008d43aef0771472876bea6d828ba0d Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 18:10:31 +1030 Subject: [PATCH 041/121] N64: Fix confict with stdio --- src/n64/n64_virtualpak.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/n64/n64_virtualpak.c b/src/n64/n64_virtualpak.c index 25807acf..292ea082 100644 --- a/src/n64/n64_virtualpak.c +++ b/src/n64/n64_virtualpak.c @@ -290,7 +290,7 @@ void n64_virtualpak_update(n64_mempack *vpak) //Print generic headers and footers n64_virtualpak_write_string("USB64 - RYZEE119", HEADING, MENU_NAME_FIELD); - sprintf_(buff, "CONTROLLER %u", controller_page + 1); + usb64_sprintf(buff, "CONTROLLER %u", controller_page + 1); n64_virtualpak_write_string(buff, SUBHEADING, MENU_NAME_FIELD); n64_virtualpak_write_string("________________", SUBHEADING + 1, MENU_NAME_FIELD); n64_virtualpak_write_string("CHANGE CONT", CHANGE_CONTROLLER, MENU_NAME_FIELD); @@ -353,7 +353,7 @@ void n64_virtualpak_update(n64_mempack *vpak) if (current_menu == MENU_CONTROLLER_SETTINGS) { - sprintf_(buff, "CONTROLLER %u", controller_page + 1); + usb64_sprintf(buff, "CONTROLLER %u", controller_page + 1); n64_virtualpak_write_string(buff, SUBHEADING + 0, MENU_NAME_FIELD); n64_virtualpak_write_string("________________", SUBHEADING + 1, MENU_NAME_FIELD); n64_virtualpak_write_string("CONT SETTINGS", SUBHEADING + 2, MENU_NAME_FIELD); @@ -396,16 +396,16 @@ void n64_virtualpak_update(n64_mempack *vpak) } //Print the current values of each setting - sprintf_(buff, "%u", settings->sensitivity[controller_page]); + usb64_sprintf(buff, "%u", settings->sensitivity[controller_page]); n64_virtualpak_write_string(buff, SUBHEADING + 4, MENU_EXT_FIELD); - sprintf_(buff, "%u", settings->deadzone[controller_page]); + usb64_sprintf(buff, "%u", settings->deadzone[controller_page]); n64_virtualpak_write_string(buff, SUBHEADING + 7, MENU_EXT_FIELD); - sprintf_(buff, "%u", settings->snap_axis[controller_page]); + usb64_sprintf(buff, "%u", settings->snap_axis[controller_page]); n64_virtualpak_write_string(buff, SUBHEADING + 10, MENU_EXT_FIELD); - sprintf_(buff, "%u", settings->octa_correct[controller_page]); + usb64_sprintf(buff, "%u", settings->octa_correct[controller_page]); n64_virtualpak_write_string(buff, SUBHEADING + 11, MENU_EXT_FIELD); vpak->virtual_selected_row = -1; From 724e2fc7010b005064bfc010150835850581f1fc Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 18:11:43 +1030 Subject: [PATCH 042/121] Remove printf submodule --- .gitmodules | 4 ---- src/lib/printf | 1 - 2 files changed, 5 deletions(-) delete mode 160000 src/lib/printf diff --git a/.gitmodules b/.gitmodules index fceed2be..0842c426 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,3 @@ -[submodule "src/printf"] - path = src/lib/printf - url = https://github.com/mpaland/printf - [submodule "src/lib/tinyusb"] path = src/lib/tinyusb url = https://github.com/hathach/tinyusb.git diff --git a/src/lib/printf b/src/lib/printf deleted file mode 160000 index d3b98468..00000000 --- a/src/lib/printf +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d3b984684bb8a8bdc48cc7a1abecb93ce59bbe3e From 3c69cd1a2809d150296b482629aab98f05680d18 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 18:13:46 +1030 Subject: [PATCH 043/121] Build: Link lpthread for linux test build --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index 57954415..fbc031be 100644 --- a/platformio.ini +++ b/platformio.ini @@ -94,3 +94,4 @@ build_flags = ${common_env_data.build_flags} -Isrc/port_null/ -DCFG_TUSB_MCU=OPT_MCU_NONE + -lpthread From dbf60439bc3d0ec83fae8010d2c200dbe4efe002 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 18:14:44 +1030 Subject: [PATCH 044/121] Printf: Readd with mods --- src/lib/printf/LICENSE | 22 + src/lib/printf/README.md | 212 +++++++++ src/lib/printf/printf.c | 914 +++++++++++++++++++++++++++++++++++++++ src/lib/printf/printf.h | 112 +++++ 4 files changed, 1260 insertions(+) create mode 100644 src/lib/printf/LICENSE create mode 100644 src/lib/printf/README.md create mode 100644 src/lib/printf/printf.c create mode 100644 src/lib/printf/printf.h diff --git a/src/lib/printf/LICENSE b/src/lib/printf/LICENSE new file mode 100644 index 00000000..8f7ebd0b --- /dev/null +++ b/src/lib/printf/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 Marco Paland + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/src/lib/printf/README.md b/src/lib/printf/README.md new file mode 100644 index 00000000..2122653e --- /dev/null +++ b/src/lib/printf/README.md @@ -0,0 +1,212 @@ +# A printf / sprintf Implementation for Embedded Systems + +[![Build Status](https://travis-ci.org/mpaland/printf.svg?branch=master)](https://travis-ci.org/mpaland/printf) +[![codecov](https://codecov.io/gh/mpaland/printf/branch/master/graph/badge.svg)](https://codecov.io/gh/mpaland/printf) +[![Coverity Status](https://img.shields.io/coverity/scan/14180.svg)](https://scan.coverity.com/projects/mpaland-printf) +[![Github Issues](https://img.shields.io/github/issues/mpaland/printf.svg)](http://github.com/mpaland/printf/issues) +[![Github Releases](https://img.shields.io/github/release/mpaland/printf.svg)](https://github.com/mpaland/printf/releases) +[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/mpaland/avl_array/master/LICENSE) + +This is a tiny but **fully loaded** printf, sprintf and (v)snprintf implementation. +Primarily designed for usage in embedded systems, where printf is not available due to memory issues or in avoidance of linking against libc. +Using the standard libc printf may pull **a lot** of unwanted library stuff and can bloat code size about 20k or is not 100% thread safe. In this cases the following implementation can be used. +Absolutely **NO dependencies** are required, *printf.c* brings all necessary routines, even its own fast `ftoa` (floating point), `ntoa` (decimal) conversion. + +If memory footprint is really a critical issue, floating point, exponential and 'long long' support and can be turned off via the `PRINTF_DISABLE_SUPPORT_FLOAT`, `PRINTF_DISABLE_SUPPORT_EXPONENTIAL` and `PRINTF_DISABLE_SUPPORT_LONG_LONG` compiler switches. +When using printf (instead of sprintf/snprintf) you have to provide your own `_putchar()` low level function as console/serial output. + + +## 2020 announcement +This project is not dead! I just had no time in 2019 for sufficient support, sorry. +Within the next weeks, I will have a look to all PRs and open issues. +Thank you all for supporting this project. + + +## Highlights and Design Goals + +There is a boatload of so called 'tiny' printf implementations around. So why this one? +I've tested many implementations, but most of them have very limited flag/specifier support, a lot of other dependencies or are just not standard compliant and failing most of the test suite. +Therefore I decided to write an own, final implementation which meets the following items: + + - Very small implementation (around 600 code lines) + - NO dependencies, no libs, just one module file + - Support of all important flags, width and precision sub-specifiers (see below) + - Support of decimal/floating number representation (with an own fast itoa/ftoa) + - Reentrant and thread-safe, malloc free, no static vars/buffers + - LINT and compiler L4 warning free, mature, coverity clean, automotive ready + - Extensive test suite (> 400 test cases) passing + - Simply the best *printf* around the net + - MIT license + + +## Usage + +Add/link *printf.c* to your project and include *printf.h*. That's it. +Implement your low level output function needed for `printf()`: +```C +void _putchar(char character) +{ + // send char to console etc. +} +``` + +Usage is 1:1 like the according stdio.h library version: +```C +int printf(const char* format, ...); +int sprintf(char* buffer, const char* format, ...); +int snprintf(char* buffer, size_t count, const char* format, ...); +int vsnprintf(char* buffer, size_t count, const char* format, va_list va); + +// use output function (instead of buffer) for streamlike interface +int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...); +``` + +**Due to general security reasons it is highly recommended to prefer and use `snprintf` (with the max buffer size as `count` parameter) instead of `sprintf`.** +`sprintf` has no buffer limitation, so when needed - use it really with care! + +### Streamlike Usage +Besides the regular standard `printf()` functions, this module also provides `fctprintf()`, which takes an output function as first parameter to build a streamlike output like `fprintf()`: +```C +// define the output function +void my_stream_output(char character, void* arg) +{ + // opt. evaluate the argument and send the char somewhere +} + +{ + // in your code + void* arg = (void*)100; // this argument is passed to the output function + fctprintf(&my_stream_output, arg, "This is a test: %X", 0xAA); + fctprintf(&my_stream_output, nullptr, "Send to null dev"); +} +``` + +## Format Specifiers + +A format specifier follows this prototype: `%[flags][width][.precision][length]type` +The following format specifiers are supported: + + +### Supported Types + +| Type | Output | +|--------|--------| +| d or i | Signed decimal integer | +| u | Unsigned decimal integer | +| b | Unsigned binary | +| o | Unsigned octal | +| x | Unsigned hexadecimal integer (lowercase) | +| X | Unsigned hexadecimal integer (uppercase) | +| f or F | Decimal floating point | +| e or E | Scientific-notation (exponential) floating point | +| g or G | Scientific or decimal floating point | +| c | Single character | +| s | String of characters | +| p | Pointer address | +| % | A % followed by another % character will write a single % | + + +### Supported Flags + +| Flags | Description | +|-------|-------------| +| - | Left-justify within the given field width; Right justification is the default. | +| + | Forces to precede the result with a plus or minus sign (+ or -) even for positive numbers.
By default, only negative numbers are preceded with a - sign. | +| (space) | If no sign is going to be written, a blank space is inserted before the value. | +| # | Used with o, b, x or X specifiers the value is preceded with 0, 0b, 0x or 0X respectively for values different than zero.
Used with f, F it forces the written output to contain a decimal point even if no more digits follow. By default, if no digits follow, no decimal point is written. | +| 0 | Left-pads the number with zeros (0) instead of spaces when padding is specified (see width sub-specifier). | + + +### Supported Width + +| Width | Description | +|----------|-------------| +| (number) | Minimum number of characters to be printed. If the value to be printed is shorter than this number, the result is padded with blank spaces. The value is not truncated even if the result is larger. | +| * | The width is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted. | + + +### Supported Precision + +| Precision | Description | +|-----------|-------------| +| .number | For integer specifiers (d, i, o, u, x, X): precision specifies the minimum number of digits to be written. If the value to be written is shorter than this number, the result is padded with leading zeros. The value is not truncated even if the result is longer. A precision of 0 means that no character is written for the value 0.
For f and F specifiers: this is the number of digits to be printed after the decimal point. **By default, this is 6, maximum is 9**.
For s: this is the maximum number of characters to be printed. By default all characters are printed until the ending null character is encountered.
If the period is specified without an explicit value for precision, 0 is assumed. | +| .* | The precision is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted. | + + +### Supported Length + +The length sub-specifier modifies the length of the data type. + +| Length | d i | u o x X | +|--------|------|---------| +| (none) | int | unsigned int | +| hh | char | unsigned char | +| h | short int | unsigned short int | +| l | long int | unsigned long int | +| ll | long long int | unsigned long long int (if PRINTF_SUPPORT_LONG_LONG is defined) | +| j | intmax_t | uintmax_t | +| z | size_t | size_t | +| t | ptrdiff_t | ptrdiff_t (if PRINTF_SUPPORT_PTRDIFF_T is defined) | + + +### Return Value + +Upon successful return, all functions return the number of characters written, _excluding_ the terminating null character used to end the string. +Functions `snprintf()` and `vsnprintf()` don't write more than `count` bytes, _including_ the terminating null byte ('\0'). +Anyway, if the output was truncated due to this limit, the return value is the number of characters that _could_ have been written. +Notice that a value equal or larger than `count` indicates a truncation. Only when the returned value is non-negative and less than `count`, +the string has been completely written. +If any error is encountered, `-1` is returned. + +If `buffer` is set to `NULL` (`nullptr`) nothing is written and just the formatted length is returned. +```C +int length = sprintf(NULL, "Hello, world"); // length is set to 12 +``` + + +## Compiler Switches/Defines + +| Name | Default value | Description | +|------|---------------|-------------| +| PRINTF_INCLUDE_CONFIG_H | undefined | Define this as compiler switch (e.g. `gcc -DPRINTF_INCLUDE_CONFIG_H`) to include a "printf_config.h" definition file | +| PRINTF_NTOA_BUFFER_SIZE | 32 | ntoa (integer) conversion buffer size. This must be big enough to hold one converted numeric number _including_ leading zeros, normally 32 is a sufficient value. Created on the stack | +| PRINTF_FTOA_BUFFER_SIZE | 32 | ftoa (float) conversion buffer size. This must be big enough to hold one converted float number _including_ leading zeros, normally 32 is a sufficient value. Created on the stack | +| PRINTF_DEFAULT_FLOAT_PRECISION | 6 | Define the default floating point precision | +| PRINTF_MAX_FLOAT | 1e9 | Define the largest suitable value to be printed with %f, before using exponential representation | +| PRINTF_DISABLE_SUPPORT_FLOAT | undefined | Define this to disable floating point (%f) support | +| PRINTF_DISABLE_SUPPORT_EXPONENTIAL | undefined | Define this to disable exponential floating point (%e) support | +| PRINTF_DISABLE_SUPPORT_LONG_LONG | undefined | Define this to disable long long (%ll) support | +| PRINTF_DISABLE_SUPPORT_PTRDIFF_T | undefined | Define this to disable ptrdiff_t (%t) support | + + +## Caveats +None anymore (finally). + + +## Test Suite +For testing just compile, build and run the test suite located in `test/test_suite.cpp`. This uses the [catch](https://github.com/catchorg/Catch2) framework for unit-tests, which is auto-adding main(). +Running with the `--wait-for-keypress exit` option waits for the enter key after test end. + + +## Projects Using printf +- [turnkeyboard](https://github.com/mpaland/turnkeyboard) uses printf as log and generic tty (formatting) output. +- printf is part of [embeddedartistry/libc](https://github.com/embeddedartistry/libc), a libc targeted for embedded systems usage. +- The [Hatchling Platform]( https://github.com/adrian3git/HatchlingPlatform) uses printf. + +(Just send me a mail/issue/PR to get *your* project listed here) + + +## Contributing + +0. Give this project a :star: +1. Create an issue and describe your idea +2. [Fork it](https://github.com/mpaland/printf/fork) +3. Create your feature branch (`git checkout -b my-new-feature`) +4. Commit your changes (`git commit -am 'Add some feature'`) +5. Publish the branch (`git push origin my-new-feature`) +6. Create a new pull request +7. Profit! :heavy_check_mark: + + +## License +printf is written under the [MIT license](http://www.opensource.org/licenses/MIT). diff --git a/src/lib/printf/printf.c b/src/lib/printf/printf.c new file mode 100644 index 00000000..406dca99 --- /dev/null +++ b/src/lib/printf/printf.c @@ -0,0 +1,914 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. These routines are thread +// safe and reentrant! +// Use this instead of the bloated standard/newlib printf cause these use +// malloc for printf (and may not be thread safe). +// +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "printf.h" + + +// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the +// printf_config.h header file +// default: undefined +#ifdef PRINTF_INCLUDE_CONFIG_H +#include "printf_config.h" +#endif + + +// 'ntoa' conversion buffer size, this must be big enough to hold one converted +// numeric number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_NTOA_BUFFER_SIZE +#define PRINTF_NTOA_BUFFER_SIZE 32U +#endif + +// 'ftoa' conversion buffer size, this must be big enough to hold one converted +// float number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_FTOA_BUFFER_SIZE +#define PRINTF_FTOA_BUFFER_SIZE 32U +#endif + +// support for the floating point type (%f) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_FLOAT +#define PRINTF_SUPPORT_FLOAT +#endif + +// support for exponential floating point notation (%e/%g) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL +#define PRINTF_SUPPORT_EXPONENTIAL +#endif + +// define the default floating point precision +// default: 6 digits +#ifndef PRINTF_DEFAULT_FLOAT_PRECISION +#define PRINTF_DEFAULT_FLOAT_PRECISION 6U +#endif + +// define the largest float suitable to print with %f +// default: 1e9 +#ifndef PRINTF_MAX_FLOAT +#define PRINTF_MAX_FLOAT 1e9 +#endif + +// support for the long long types (%llu or %p) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG +#define PRINTF_SUPPORT_LONG_LONG +#endif + +// support for the ptrdiff_t type (%t) +// ptrdiff_t is normally defined in as long or long long type +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T +#define PRINTF_SUPPORT_PTRDIFF_T +#endif + +/////////////////////////////////////////////////////////////////////////////// + +// internal flag definitions +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_PRECISION (1U << 10U) +#define FLAGS_ADAPT_EXP (1U << 11U) + + +// import float.h for DBL_MAX +#if defined(PRINTF_SUPPORT_FLOAT) +#include +#endif + + +// output function type +typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); + + +// wrapper (used as buffer) for output function type +typedef struct { + void (*fct)(char character, void* arg); + void* arg; +} out_fct_wrap_type; + + +// internal buffer output +static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) +{ + if (idx < maxlen) { + ((char*)buffer)[idx] = character; + } +} + + +// internal null output +static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)character; (void)buffer; (void)idx; (void)maxlen; +} + + +// internal _putchar wrapper +static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)buffer; (void)idx; (void)maxlen; + if (character) { + _putchar(character); + } +} + + +// internal output function wrapper +static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) +{ + (void)idx; (void)maxlen; + if (character) { + // buffer is the output fct pointer + ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); + } +} + + +// internal secure strlen +// \return The length of the string (excluding the terminating 0) limited by 'maxsize' +static inline unsigned int _strnlen_s(const char* str, size_t maxsize) +{ + const char* s; + for (s = str; *s && maxsize--; ++s); + return (unsigned int)(s - str); +} + + +// internal test if char is a digit (0-9) +// \return true if char is a digit +static inline bool _is_digit(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + + +// internal ASCII string to unsigned int conversion +static unsigned int _atoi(const char** str) +{ + unsigned int i = 0U; + while (_is_digit(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; +} + + +// output the specified string in reverse, taking care of any zero-padding +static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags) +{ + const size_t start_idx = idx; + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + while (len) { + out(buf[--len], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} + + +// internal itoa format +static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) +{ + // pad leading zeros + if (!(flags & FLAGS_LEFT)) { + if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + // handle hash + if (flags & FLAGS_HASH) { + if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) { + len--; + if (len && (base == 16U)) { + len--; + } + } + if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'x'; + } + else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'X'; + } + else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'b'; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_NTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + + +// internal itoa for 'long' type +static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} + + +// internal itoa for 'long long' type +#if defined(PRINTF_SUPPORT_LONG_LONG) +static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { + flags &= ~FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} +#endif // PRINTF_SUPPORT_LONG_LONG + + +#if defined(PRINTF_SUPPORT_FLOAT) + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT +static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); +#endif + + +// internal ftoa for fixed decimal floating point +static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; + + // powers of 10 + static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + + // test for special values + if (value != value) + return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); + if (value < -DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); + if (value > DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags); + + // test for very large values + // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad + if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); +#else + return 0U; +#endif + } + + // test for negative + bool negative = false; + if (value < 0) { + negative = true; + value = 0 - value; + } + + // set default precision, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; + + if (diff > 0.5) { + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } + else if (diff < 0.5) { + } + else if ((frac == 0U) || (frac & 1U)) { + // if halfway, round up if odd OR if last digit is 0 + ++frac; + } + + if (prec == 0U) { + diff = value - (double)whole; + if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } + else { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) { + break; + } + } + // add extra 0s + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed + while (len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) { + break; + } + } + + // pad leading zeros + if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { + if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_FTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } + else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + + +#if defined(PRINTF_SUPPORT_EXPONENTIAL) +// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse +static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + // check for NaN and special values + if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { + return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); + } + + // determine the sign + const bool negative = value < 0; + if (negative) { + value = -value; + } + + // default precision + if (!(flags & FLAGS_PRECISION)) { + prec = PRINTF_DEFAULT_FLOAT_PRECISION; + } + + // determine the decimal exponent + // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) + union { + uint64_t U; + double F; + } conv; + + conv.F = value; + int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 + conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) + // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 + int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); + // now we want to compute 10^expval but we want to be sure it won't overflow + exp2 = (int)(expval * 3.321928094887362 + 0.5); + const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = (uint64_t)(exp2 + 1023) << 52U; + // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + // correct for rounding errors + if (value < conv.F) { + expval--; + conv.F /= 10; + } + + // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters + unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; + + // in "%g" mode, "prec" is the number of *significant figures* not decimals + if (flags & FLAGS_ADAPT_EXP) { + // do we want to fall-back to "%f" mode? + if ((value >= 1e-4) && (value < 1e6)) { + if ((int)prec > expval) { + prec = (unsigned)((int)prec - expval - 1); + } + else { + prec = 0; + } + flags |= FLAGS_PRECISION; // make sure _ftoa respects precision + // no characters in exponent + minwidth = 0U; + expval = 0; + } + else { + // we use one sigfig for the whole part + if ((prec > 0) && (flags & FLAGS_PRECISION)) { + --prec; + } + } + } + + // will everything fit? + unsigned int fwidth = width; + if (width > minwidth) { + // we didn't fall-back so subtract the characters required for the exponent + fwidth -= minwidth; + } else { + // not enough characters, so go back to default sizing + fwidth = 0U; + } + if ((flags & FLAGS_LEFT) && minwidth) { + // if we're padding on the right, DON'T pad the floating part + fwidth = 0U; + } + + // rescale the float value + if (expval) { + value /= conv.F; + } + + // output the floating part + const size_t start_idx = idx; + idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP); + + // output the exponent part + if (minwidth) { + // output the exponential symbol + out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); + // output the exponent value + idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS); + // might need to right-pad spaces + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) out(' ', buffer, idx++, maxlen); + } + } + return idx; +} +#endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + + +// internal vsnprintf +static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) +{ + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if (!buffer) { + // use null output function + out = _out_null; + } + + while (*format) + { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; + } + else { + // yes, evaluate it + format++; + } + + // evaluate flags + flags = 0U; + do { + switch (*format) { + case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break; + case '-': flags |= FLAGS_LEFT; format++; n = 1U; break; + case '+': flags |= FLAGS_PLUS; format++; n = 1U; break; + case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break; + case '#': flags |= FLAGS_HASH; format++; n = 1U; break; + default : n = 0U; break; + } + } while (n); + + // evaluate width field + width = 0U; + if (_is_digit(*format)) { + width = _atoi(&format); + } + else if (*format == '*') { + const int w = va_arg(va, int); + if (w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } + else { + width = (unsigned int)w; + } + format++; + } + + // evaluate precision field + precision = 0U; + if (*format == '.') { + flags |= FLAGS_PRECISION; + format++; + if (_is_digit(*format)) { + precision = _atoi(&format); + } + else if (*format == '*') { + const int prec = (int)va_arg(va, int); + precision = prec > 0 ? (unsigned int)prec : 0U; + format++; + } + } + + // evaluate length field + switch (*format) { + case 'l' : + flags |= FLAGS_LONG; + format++; + if (*format == 'l') { + flags |= FLAGS_LONG_LONG; + format++; + } + break; + case 'h' : + flags |= FLAGS_SHORT; + format++; + if (*format == 'h') { + flags |= FLAGS_CHAR; + format++; + } + break; +#if defined(PRINTF_SUPPORT_PTRDIFF_T) + case 't' : + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; +#endif + case 'j' : + flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'z' : + flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + default : + break; + } + + // evaluate specifier + switch (*format) { + case 'd' : + case 'i' : + case 'u' : + case 'x' : + case 'X' : + case 'o' : + case 'b' : { + // set the base + unsigned int base; + if (*format == 'x' || *format == 'X') { + base = 16U; + } + else if (*format == 'o') { + base = 8U; + } + else if (*format == 'b') { + base = 2U; + } + else { + base = 10U; + flags &= ~FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') { + flags |= FLAGS_UPPERCASE; + } + + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) { + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + } + + // ignore '0' flag when precision is given + if (flags & FLAGS_PRECISION) { + flags &= ~FLAGS_ZEROPAD; + } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) { + // signed + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + const long long value = va_arg(va, long long); + idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + const long value = va_arg(va, long); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + else { + const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int); + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + } + else { + // unsigned + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); +#endif + } + else if (flags & FLAGS_LONG) { + idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); + } + else { + const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int); + idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); + } + } + format++; + break; + } +#if defined(PRINTF_SUPPORT_FLOAT) + case 'f' : + case 'F' : + if (*format == 'F') flags |= FLAGS_UPPERCASE; + idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#if defined(PRINTF_SUPPORT_EXPONENTIAL) + case 'e': + case 'E': + case 'g': + case 'G': + if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP; + if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE; + idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + case 'c' : { + unsigned int l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's' : { + const char* p = va_arg(va, char*); + unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1); + // pre padding + if (flags & FLAGS_PRECISION) { + l = (l < precision ? l : precision); + } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p' : { + width = sizeof(void*) * 2U; + flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; +#if defined(PRINTF_SUPPORT_LONG_LONG) + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) { + idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags); + } + else { +#endif + idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags); +#if defined(PRINTF_SUPPORT_LONG_LONG) + } +#endif + format++; + break; + } + + case '%' : + out('%', buffer, idx++, maxlen); + format++; + break; + + default : + out(*format, buffer, idx++, maxlen); + format++; + break; + } + } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx; +} + + +/////////////////////////////////////////////////////////////////////////////// + +int usb64_printf(const char* format, ...) +{ + va_list va; + va_start(va, format); + char buffer[1]; + const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + + +int usb64_sprintf(char* buffer, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + + +int usb64_snprintf(char* buffer, size_t count, const char* format, ...) +{ + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); + va_end(va); + return ret; +} + + +int usb64_vprintf(const char* format, va_list va) +{ + char buffer[1]; + return _vsnprintf(_out_char, buffer, (size_t)-1, format, va); +} + + +int usb64_vsnprintf(char* buffer, size_t count, const char* format, va_list va) +{ + return _vsnprintf(_out_buffer, buffer, count, format, va); +} + + +int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...) +{ + va_list va; + va_start(va, format); + const out_fct_wrap_type out_fct_wrap = { out, arg }; + const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); + va_end(va); + return ret; +} diff --git a/src/lib/printf/printf.h b/src/lib/printf/printf.h new file mode 100644 index 00000000..18cca76c --- /dev/null +++ b/src/lib/printf/printf.h @@ -0,0 +1,112 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. +// Use this instead of bloated standard/newlib printf. +// These routines are thread safe and reentrant. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _PRINTF_H_ +#define _PRINTF_H_ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Output a character to a custom device like UART, used by the printf() function + * This function is declared here only. You have to write your custom implementation somewhere + * \param character Character to output + */ +void _putchar(char character); + + +/** + * Tiny printf implementation + * You have to implement _putchar if you use printf() + * To avoid conflicts with the regular printf() API it is overridden by macro defines + * and internal underscore-appended functions like usb64_printf() are used + * \param format A string that specifies the format of the output + * \return The number of characters that are written into the array, not counting the terminating null character + */ +int usb64_printf(const char* format, ...); + + +/** + * Tiny sprintf implementation + * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! + * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! + * \param format A string that specifies the format of the output + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ +int usb64_sprintf(char* buffer, const char* format, ...); + + +/** + * Tiny snprintf/vsnprintf implementation + * \param buffer A pointer to the buffer where to store the formatted string + * \param count The maximum number of characters to store in the buffer, including a terminating null character + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that COULD have been written into the buffer, not counting the terminating + * null character. A value equal or larger than count indicates truncation. Only when the returned value + * is non-negative and less than count, the string has been completely written. + */ +int usb64_snprintf(char* buffer, size_t count, const char* format, ...); +int usb64_vsnprintf(char* buffer, size_t count, const char* format, va_list va); + + +/** + * Tiny vprintf implementation + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ +int usb64_vprintf(const char* format, va_list va); + + +/** + * printf with output function + * You may use this as dynamic alternative to printf() with its fixed _putchar() output + * \param out An output function which takes one character and an argument pointer + * \param arg An argument pointer for user data passed to output function + * \param format A string that specifies the format of the output + * \return The number of characters that are sent to the output function, not counting the terminating null character + */ +int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...); + + +#ifdef __cplusplus +} +#endif + + +#endif // _PRINTF_H_ From 7583ec6cd6d1b2be4dac6bc0993ca2b650e4ee51 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 18:32:11 +1030 Subject: [PATCH 045/121] TFT: Dont set pointer twice --- src/port_teensy41/tft_t4.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/port_teensy41/tft_t4.cpp b/src/port_teensy41/tft_t4.cpp index 3c08509a..e2559a17 100644 --- a/src/port_teensy41/tft_t4.cpp +++ b/src/port_teensy41/tft_t4.cpp @@ -95,8 +95,6 @@ void tft_dev_init() #if TFT_USE_FRAMEBUFFER static c_surface surface(TFT_WIDTH, TFT_HEIGHT, 2, Z_ORDER_LEVEL_0); static c_display display(_framebuffer, TFT_WIDTH, TFT_HEIGHT, &surface); - psurface_guilite = &surface; - pdisplay_guilite = &display; tft.setFrameBuffer((uint16_t *)_framebuffer); tft.useFrameBuffer(true); #else From 755ab5b63ce3094a233ed3fd20886e65d89a79ab Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 30 Nov 2021 18:48:49 +1030 Subject: [PATCH 046/121] Main: Dont use stdio vprintf --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 98bbdd7d..6dcc5f97 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,7 +70,7 @@ extern "C" int CFG_TUSB_DEBUG_PRINTF(const char *format, ...) { va_list args; va_start(args, format); - vprintf(format, args); + usb64_vprintf(format, args); return 1; } #endif From c1cbf5782b606bcbbdb2ac1af27a0b679fe38371 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 1 Dec 2021 08:20:33 +1030 Subject: [PATCH 047/121] TinyUSB: Use my own TinyUSB fork --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 0842c426..9410602c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "src/lib/tinyusb"] path = src/lib/tinyusb - url = https://github.com/hathach/tinyusb.git + url = https://github.com/Ryzee119/tinyusb.git [submodule "src/teensy41/ILI9341_t3n"] path = src/port_teensy41/ILI9341_t3n url = https://github.com/KurtE/ILI9341_t3n.git From 7d693b285efb57e8ca417a750a519cb436fb59d0 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 1 Dec 2021 09:41:37 +1030 Subject: [PATCH 048/121] TinyUSB: Update submodule --- src/lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tinyusb b/src/lib/tinyusb index 1efdc168..39dfa850 160000 --- a/src/lib/tinyusb +++ b/src/lib/tinyusb @@ -1 +1 @@ -Subproject commit 1efdc16816f001657944c5349507eb46d1fa0270 +Subproject commit 39dfa850db7a90526fa5d474a4d54d9b11695a3a From d81ccd94bbc7ef445ba550afd9b593ceeb180396 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 1 Dec 2021 09:54:57 +1030 Subject: [PATCH 049/121] GuiLite: Suppress warnings --- src/lib/GuiLite.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/lib/GuiLite.h b/src/lib/GuiLite.h index 8ad6dd15..b6652636 100644 --- a/src/lib/GuiLite.h +++ b/src/lib/GuiLite.h @@ -1,3 +1,8 @@ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wreorder" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" + #pragma once #define REAL_TIME_TASK_CYCLE_MS 50 @@ -4334,4 +4339,5 @@ WND_TREE g_number_board_children[] = {&s_key_enter,'\n', 0, POS_X(3), POS_Y(2), KEY_WIDTH, KEY_HEIGHT * 2 + 2}, {0,0,0,0,0,0,0} }; -#endif \ No newline at end of file +#endif +#pragma GCC diagnostic pop From f4566720285d59ae3890a871bb79b09e52acde78 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 1 Dec 2021 10:01:58 +1030 Subject: [PATCH 050/121] usb64: Fix some warnings --- src/main.cpp | 2 +- src/tft.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6dcc5f97..899e21e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -458,7 +458,7 @@ void loop() //Create the filename char filename[32]; - snprintf(filename, sizeof(filename), "MEMPAK%02u%s", mempak_bank, MEMPAK_SAVE_EXT); + snprintf(filename, sizeof(filename), "MEMPAK%02u%s", (unsigned int)mempak_bank, MEMPAK_SAVE_EXT); //Scan controllers to see if mempack is in use for (uint32_t i = 0; i < MAX_CONTROLLERS; i++) diff --git a/src/tft.cpp b/src/tft.cpp index e452804d..d01829ad 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -76,7 +76,7 @@ static const char *n64_peri_to_string(n64_input_dev_t *c) if (c->mempack->virtual_is_active) return "VIRTUAL PAK"; - snprintf(text_buff, sizeof(text_buff), "MPAK (BANK %u)", c->mempack->id); + snprintf(text_buff, sizeof(text_buff), "MPAK (BANK %u)", (unsigned int)c->mempack->id); return text_buff; case PERI_TPAK: snprintf(text_buff, sizeof(text_buff), "TPAK (%s)", (c->tpak->gbcart->rom == NULL) ? "NO ROM" : c->tpak->gbcart->title); From d049e347ae6428176e5278148f2734cd8005a73f Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 4 Dec 2021 07:53:14 +1030 Subject: [PATCH 051/121] null: Add millis to HAL --- src/port_null/hal_null.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/port_null/hal_null.cpp b/src/port_null/hal_null.cpp index 232bbb6e..7f31ee3e 100644 --- a/src/port_null/hal_null.cpp +++ b/src/port_null/hal_null.cpp @@ -149,6 +149,16 @@ uint32_t n64hal_hs_tick_get() return 0; } +/* + * Function: Get the number of milliseconds since power up. + * ---------------------------- + * Returns: 32 bit tick value at 1000Hz. + */ +uint32_t n64hal_millis() +{ + return 0; +} + /* * Function: Flips the gpio pin direction from an output (driven low) to an input (pulled up) * for the controller passed by controller. From 59075844b0da9d10116edac417f2f48054a50364 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 4 Dec 2021 13:25:42 +1030 Subject: [PATCH 052/121] T4: Move usb64_conf file to port fodler --- src/{ => port_teensy41}/usb64_conf.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{ => port_teensy41}/usb64_conf.h (100%) diff --git a/src/usb64_conf.h b/src/port_teensy41/usb64_conf.h similarity index 100% rename from src/usb64_conf.h rename to src/port_teensy41/usb64_conf.h From d1c8a35528e310da670b1b9bfb1c26735d9f8f76 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 4 Dec 2021 13:26:22 +1030 Subject: [PATCH 053/121] Main: Loop properly when not using Arduino --- src/main.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 899e21e9..d911119f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -82,11 +82,14 @@ void loop(); #include #include #include -int main() +int main(void) { startup_early_hook(); setup(); - loop(); + while(1) + { + loop(); + } } #endif From 4d16a8c73eb5e5a14b85ad4450429a4e22408c62 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 4 Dec 2021 13:27:42 +1030 Subject: [PATCH 054/121] TFT: Store font on ext flash --- src/tft/Arial_14.cpp | 173 ++++++++++++++++++++++--------------------- src/tft/Arial_19.cpp | 173 ++++++++++++++++++++++--------------------- 2 files changed, 174 insertions(+), 172 deletions(-) diff --git a/src/tft/Arial_14.cpp b/src/tft/Arial_14.cpp index 85e41bea..efebcae1 100644 --- a/src/tft/Arial_14.cpp +++ b/src/tft/Arial_14.cpp @@ -1,176 +1,177 @@ +#include "usb64_conf.h" #include "GuiLite.h" -static const unsigned char _32[] = { +static const unsigned char _32[] PROGMEM = { 0, 42, }; -static const unsigned char _33[] = { +static const unsigned char _33[] PROGMEM = { 0, 6, 36, 1, 197, 1, 36, 1, 197, 1, 36, 1, 153, 1, 36, 1, 153, 1, 0, 1, 153, 1, 0, 1, 111, 1, 0, 2, 36, 1, 197, 1, 0, 6, }; -static const unsigned char _35[] = { +static const unsigned char _35[] PROGMEM = { 0, 20, 153, 1, 73, 2, 153, 1, 0, 2, 197, 1, 36, 1, 111, 1, 73, 1, 153, 1, 255, 5, 0, 1, 36, 1, 197, 1, 0, 1, 255, 1, 0, 2, 111, 2, 36, 1, 197, 1, 0, 1, 153, 1, 255, 5, 0, 1, 197, 1, 36, 1, 153, 1, 73, 1, 0, 2, 197, 1, 0, 1, 197, 1, 36, 1, 0, 19, }; -static const unsigned char _37[] = { +static const unsigned char _37[] PROGMEM = { 0, 31, 111, 1, 255, 2, 0, 2, 36, 1, 255, 1, 0, 3, 255, 1, 0, 1, 111, 2, 0, 1, 153, 1, 73, 1, 0, 3, 255, 1, 0, 1, 111, 2, 73, 1, 197, 1, 0, 4, 111, 1, 255, 2, 0, 1, 197, 1, 36, 1, 0, 7, 73, 1, 153, 1, 73, 1, 255, 2, 36, 1, 0, 4, 197, 1, 36, 1, 197, 1, 36, 1, 73, 1, 153, 1, 0, 3, 111, 2, 0, 1, 197, 1, 36, 1, 73, 1, 153, 1, 0, 3, 255, 1, 0, 2, 73, 1, 255, 2, 36, 1, 0, 30, }; -static const unsigned char _39[] = { +static const unsigned char _39[] PROGMEM = { 0, 6, 36, 1, 197, 1, 36, 1, 197, 1, 0, 1, 153, 1, 0, 16, }; -static const unsigned char _40[] = { +static const unsigned char _40[] PROGMEM = { 0, 14, 36, 1, 197, 1, 0, 2, 197, 1, 0, 2, 73, 1, 111, 1, 0, 2, 153, 1, 73, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 153, 1, 73, 1, 0, 2, 73, 1, 111, 1, 0, 3, 197, 1, 0, 3, 36, 1, 197, 1, 0, 4, }; -static const unsigned char _41[] = { +static const unsigned char _41[] PROGMEM = { 0, 13, 153, 1, 36, 1, 0, 3, 197, 1, 0, 3, 111, 1, 73, 1, 0, 2, 36, 1, 153, 1, 0, 2, 36, 1, 197, 1, 0, 2, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 2, 111, 1, 73, 1, 0, 2, 197, 1, 0, 2, 153, 1, 36, 1, 0, 5, }; -static const unsigned char _43[] = { +static const unsigned char _43[] PROGMEM = { 0, 33, 197, 1, 0, 5, 197, 1, 0, 3, 255, 5, 0, 3, 197, 1, 0, 5, 197, 1, 0, 26, }; -static const unsigned char _44[] = { +static const unsigned char _44[] PROGMEM = { 0, 31, 153, 1, 73, 1, 0, 1, 73, 2, 0, 1, 111, 1, 0, 4, }; -static const unsigned char _45[] = { +static const unsigned char _45[] PROGMEM = { 0, 32, 73, 1, 255, 3, 0, 20, }; -static const unsigned char _46[] = { +static const unsigned char _46[] PROGMEM = { 0, 31, 153, 1, 73, 1, 0, 9, }; -static const unsigned char _47[] = { +static const unsigned char _47[] PROGMEM = { 0, 11, 111, 1, 0, 2, 197, 1, 0, 1, 36, 1, 197, 1, 0, 1, 73, 1, 111, 1, 0, 1, 153, 1, 73, 1, 0, 1, 255, 1, 0, 1, 73, 1, 153, 1, 0, 1, 111, 2, 0, 10, }; -static const unsigned char _48[] = { +static const unsigned char _48[] PROGMEM = { 0, 20, 255, 2, 153, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 153, 1, 111, 1, 0, 1, 197, 1, 73, 1, 0, 2, 255, 2, 153, 1, 0, 19, }; -static const unsigned char _49[] = { +static const unsigned char _49[] PROGMEM = { 0, 21, 153, 1, 73, 1, 0, 3, 153, 1, 255, 1, 73, 1, 0, 2, 111, 1, 73, 1, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 19, }; -static const unsigned char _50[] = { +static const unsigned char _50[] PROGMEM = { 0, 19, 111, 1, 255, 3, 0, 1, 36, 1, 255, 1, 0, 2, 111, 1, 153, 1, 0, 4, 36, 1, 197, 1, 0, 4, 153, 1, 73, 1, 0, 3, 153, 1, 111, 1, 0, 3, 197, 1, 111, 1, 0, 3, 197, 1, 73, 1, 0, 3, 73, 1, 255, 4, 197, 1, 0, 18, }; -static const unsigned char _51[] = { +static const unsigned char _51[] PROGMEM = { 0, 19, 73, 1, 255, 2, 153, 1, 0, 2, 255, 1, 0, 2, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 2, 36, 1, 255, 1, 153, 1, 0, 5, 73, 1, 153, 1, 0, 4, 36, 1, 197, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 73, 1, 255, 2, 197, 1, 0, 19, }; -static const unsigned char _52[] = { +static const unsigned char _52[] PROGMEM = { 0, 21, 36, 1, 197, 1, 0, 4, 197, 2, 0, 3, 111, 1, 153, 1, 197, 1, 0, 2, 36, 1, 197, 1, 36, 1, 197, 1, 0, 2, 197, 1, 36, 2, 197, 1, 0, 1, 36, 1, 255, 4, 197, 1, 0, 3, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 19, }; -static const unsigned char _53[] = { +static const unsigned char _53[] PROGMEM = { 0, 19, 73, 1, 255, 3, 73, 1, 0, 1, 111, 2, 0, 4, 197, 1, 73, 1, 0, 4, 255, 1, 197, 1, 255, 2, 0, 3, 36, 1, 0, 1, 36, 1, 153, 1, 0, 4, 36, 1, 197, 1, 0, 1, 255, 1, 0, 2, 36, 1, 153, 1, 0, 1, 73, 1, 255, 2, 197, 1, 0, 19, }; -static const unsigned char _54[] = { +static const unsigned char _54[] PROGMEM = { 0, 19, 36, 1, 255, 3, 0, 2, 197, 1, 36, 1, 0, 1, 111, 1, 153, 1, 36, 1, 197, 1, 0, 4, 73, 1, 153, 1, 197, 1, 255, 2, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 153, 1, 73, 1, 153, 1, 0, 2, 36, 1, 197, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 36, 1, 255, 2, 197, 1, 0, 19, }; -static const unsigned char _55[] = { +static const unsigned char _55[] PROGMEM = { 0, 18, 36, 1, 255, 4, 197, 1, 0, 4, 197, 1, 73, 1, 0, 3, 73, 1, 153, 1, 0, 4, 197, 1, 36, 1, 0, 3, 73, 1, 197, 1, 0, 4, 153, 1, 73, 1, 0, 4, 197, 1, 36, 1, 0, 4, 255, 1, 0, 21, }; -static const unsigned char _56[] = { +static const unsigned char _56[] PROGMEM = { 0, 19, 36, 1, 255, 3, 0, 2, 197, 1, 36, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 2, 197, 1, 255, 1, 111, 1, 0, 2, 255, 1, 36, 1, 0, 1, 111, 1, 153, 1, 36, 1, 197, 1, 0, 3, 255, 1, 0, 1, 255, 1, 36, 1, 0, 1, 73, 1, 197, 1, 0, 1, 73, 1, 255, 3, 0, 19, }; -static const unsigned char _57[] = { +static const unsigned char _57[] PROGMEM = { 0, 19, 73, 1, 255, 2, 153, 1, 0, 2, 255, 1, 36, 1, 0, 1, 111, 2, 36, 1, 197, 1, 0, 2, 36, 1, 197, 1, 0, 1, 255, 1, 36, 1, 0, 1, 111, 1, 197, 1, 0, 1, 73, 1, 255, 2, 153, 1, 197, 1, 0, 4, 73, 1, 153, 1, 0, 1, 255, 1, 0, 2, 197, 1, 73, 1, 0, 1, 73, 1, 255, 2, 153, 1, 0, 19, }; -static const unsigned char _58[] = { +static const unsigned char _58[] PROGMEM = { 0, 16, 153, 1, 73, 1, 0, 13, 153, 1, 73, 1, 0, 9, }; -static const unsigned char _59[] = { +static const unsigned char _59[] PROGMEM = { 0, 16, 153, 1, 73, 1, 0, 13, 153, 1, 73, 1, 0, 1, 73, 2, 0, 1, 111, 1, 0, 4, }; -static const unsigned char _60[] = { +static const unsigned char _60[] PROGMEM = { 0, 34, 111, 1, 153, 1, 0, 2, 197, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 5, 197, 1, 255, 1, 111, 1, 0, 5, 111, 1, 153, 1, 0, 24, }; -static const unsigned char _61[] = { +static const unsigned char _61[] PROGMEM = { 0, 37, 255, 4, 153, 1, 0, 7, 255, 4, 153, 1, 0, 30, }; -static const unsigned char _62[] = { +static const unsigned char _62[] PROGMEM = { 0, 31, 255, 1, 36, 1, 0, 5, 197, 1, 255, 1, 153, 1, 0, 5, 73, 1, 197, 1, 0, 2, 197, 1, 255, 1, 153, 1, 0, 2, 255, 1, 36, 1, 0, 27, }; -static const unsigned char _63[] = { +static const unsigned char _63[] PROGMEM = { 0, 19, 73, 1, 255, 3, 0, 2, 255, 1, 0, 2, 73, 1, 197, 1, 0, 4, 73, 1, 197, 1, 0, 3, 73, 1, 255, 1, 0, 3, 36, 1, 255, 1, 0, 4, 73, 1, 153, 1, 0, 10, 73, 1, 153, 1, 0, 20, }; -static const unsigned char _64[] = { +static const unsigned char _64[] PROGMEM = { 0, 36, 36, 1, 255, 4, 111, 1, 0, 4, 153, 1, 255, 1, 0, 4, 197, 1, 153, 1, 0, 2, 73, 1, 197, 1, 0, 1, 153, 1, 255, 1, 197, 1, 153, 1, 73, 1, 197, 1, 73, 1, 0, 1, 197, 1, 73, 1, 111, 1, 153, 1, 0, 1, 73, 1, 255, 1, 0, 1, 73, 1, 153, 1, 0, 1, 255, 1, 0, 1, 255, 1, 36, 1, 0, 1, 36, 1, 197, 1, 0, 1, 73, 1, 153, 1, 0, 1, 255, 1, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 1, 153, 1, 111, 1, 0, 1, 255, 1, 36, 1, 255, 1, 36, 1, 0, 1, 255, 1, 111, 1, 73, 1, 255, 1, 0, 2, 153, 2, 73, 1, 255, 2, 111, 1, 255, 2, 0, 4, 197, 2, 0, 5, 197, 2, 0, 3, 111, 1, 255, 5, 36, 1, 0, 12, }; -static const unsigned char _65[] = { +static const unsigned char _65[] PROGMEM = { 0, 27, 73, 1, 197, 1, 0, 6, 197, 1, 111, 1, 73, 1, 0, 4, 73, 1, 153, 1, 36, 1, 153, 1, 0, 4, 153, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 2, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 2, 153, 1, 255, 5, 36, 1, 0, 1, 255, 1, 0, 4, 111, 3, 73, 1, 0, 5, 255, 1, 0, 24, }; -static const unsigned char _66[] = { +static const unsigned char _66[] PROGMEM = { 0, 22, 197, 1, 255, 3, 153, 1, 0, 2, 197, 1, 36, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 153, 1, 36, 1, 0, 1, 197, 1, 255, 4, 0, 2, 197, 1, 36, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 2, 153, 1, 73, 1, 0, 1, 197, 1, 255, 3, 153, 1, 0, 22, }; -static const unsigned char _67[] = { +static const unsigned char _67[] PROGMEM = { 0, 23, 111, 1, 255, 2, 153, 1, 0, 2, 111, 1, 197, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 36, 2, 0, 1, 255, 1, 0, 6, 255, 1, 0, 6, 197, 1, 36, 1, 0, 5, 111, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 255, 2, 197, 1, 0, 22, }; -static const unsigned char _68[] = { +static const unsigned char _68[] PROGMEM = { 0, 22, 255, 4, 111, 1, 0, 2, 255, 1, 0, 3, 197, 1, 73, 1, 0, 1, 255, 1, 0, 3, 73, 1, 153, 1, 0, 1, 255, 1, 0, 3, 36, 1, 197, 1, 0, 1, 255, 1, 0, 3, 36, 1, 197, 1, 0, 1, 255, 1, 0, 3, 73, 1, 153, 1, 0, 1, 255, 1, 0, 3, 197, 1, 73, 1, 0, 1, 255, 4, 111, 1, 0, 22, }; -static const unsigned char _69[] = { +static const unsigned char _69[] PROGMEM = { 0, 19, 255, 4, 111, 1, 0, 1, 255, 1, 0, 5, 255, 1, 0, 5, 255, 4, 36, 1, 0, 1, 255, 1, 0, 5, 255, 1, 0, 5, 255, 1, 0, 5, 255, 4, 153, 1, 0, 18, }; -static const unsigned char _70[] = { +static const unsigned char _70[] PROGMEM = { 0, 19, 197, 1, 255, 3, 197, 1, 0, 1, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 255, 3, 36, 1, 0, 1, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 21, }; -static const unsigned char _71[] = { +static const unsigned char _71[] PROGMEM = { 0, 26, 111, 1, 255, 3, 111, 1, 0, 2, 111, 1, 197, 1, 0, 3, 255, 1, 73, 1, 0, 1, 255, 1, 36, 1, 0, 3, 73, 1, 111, 1, 36, 1, 197, 1, 0, 6, 36, 1, 197, 1, 0, 2, 73, 1, 255, 2, 153, 1, 0, 1, 255, 1, 36, 1, 0, 3, 73, 1, 153, 1, 0, 1, 111, 1, 197, 1, 0, 3, 153, 2, 0, 2, 73, 1, 255, 3, 153, 1, 0, 25, }; -static const unsigned char _72[] = { +static const unsigned char _72[] PROGMEM = { 0, 22, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 255, 4, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 21, }; -static const unsigned char _73[] = { +static const unsigned char _73[] PROGMEM = { 0, 7, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 6, }; -static const unsigned char _74[] = { +static const unsigned char _74[] PROGMEM = { 0, 18, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 255, 2, 153, 1, 0, 16, }; -static const unsigned char _75[] = { +static const unsigned char _75[] PROGMEM = { 0, 22, 197, 1, 36, 1, 0, 2, 153, 1, 255, 1, 0, 1, 197, 1, 36, 1, 0, 1, 153, 2, 0, 2, 197, 1, 36, 1, 153, 2, 0, 3, 197, 2, 255, 1, 36, 1, 0, 3, 197, 1, 111, 2, 197, 1, 0, 3, 197, 1, 36, 1, 0, 1, 197, 1, 153, 1, 0, 2, 197, 1, 36, 1, 0, 2, 255, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 2, 73, 1, 255, 1, 0, 21, }; -static const unsigned char _76[] = { +static const unsigned char _76[] PROGMEM = { 0, 19, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 255, 4, 0, 18, }; -static const unsigned char _77[] = { +static const unsigned char _77[] PROGMEM = { 0, 25, 197, 1, 153, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 2, 0, 2, 111, 1, 197, 1, 73, 1, 0, 1, 197, 1, 111, 1, 36, 1, 0, 1, 153, 1, 111, 1, 73, 1, 0, 1, 197, 1, 73, 1, 111, 1, 0, 1, 197, 1, 111, 1, 73, 1, 0, 1, 197, 1, 36, 1, 153, 1, 36, 1, 111, 2, 73, 1, 0, 1, 197, 1, 36, 1, 153, 1, 111, 1, 73, 1, 111, 1, 73, 1, 0, 1, 197, 1, 36, 1, 111, 1, 197, 1, 0, 1, 111, 1, 73, 1, 0, 1, 197, 1, 36, 2, 197, 1, 0, 1, 111, 1, 73, 1, 0, 24, }; -static const unsigned char _78[] = { +static const unsigned char _78[] PROGMEM = { 0, 22, 197, 1, 111, 1, 0, 2, 111, 2, 0, 1, 197, 1, 255, 1, 0, 2, 111, 2, 0, 1, 197, 1, 111, 2, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 197, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 73, 1, 111, 3, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 111, 1, 0, 21, }; -static const unsigned char _79[] = { +static const unsigned char _79[] PROGMEM = { 0, 26, 111, 1, 255, 3, 0, 3, 111, 1, 197, 1, 0, 2, 73, 1, 255, 1, 0, 2, 197, 1, 36, 1, 0, 3, 153, 1, 73, 1, 0, 1, 255, 1, 0, 4, 111, 2, 0, 1, 255, 1, 0, 4, 111, 2, 0, 1, 197, 1, 36, 1, 0, 3, 153, 1, 73, 1, 0, 1, 111, 1, 197, 1, 0, 2, 73, 1, 255, 1, 0, 3, 111, 1, 255, 3, 0, 26, }; -static const unsigned char _80[] = { +static const unsigned char _80[] PROGMEM = { 0, 19, 197, 1, 255, 3, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 255, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 0, 1, 197, 1, 36, 1, 0, 2, 255, 1, 0, 1, 197, 1, 255, 3, 111, 1, 0, 1, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 21, }; -static const unsigned char _81[] = { +static const unsigned char _81[] PROGMEM = { 0, 26, 73, 1, 255, 3, 0, 3, 73, 1, 255, 1, 0, 2, 73, 1, 255, 1, 0, 2, 153, 1, 73, 1, 0, 3, 153, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 3, 111, 2, 0, 1, 197, 1, 36, 1, 0, 3, 111, 2, 0, 1, 153, 1, 73, 1, 0, 1, 73, 1, 0, 1, 153, 1, 73, 1, 0, 1, 73, 1, 255, 1, 0, 1, 73, 1, 255, 1, 197, 1, 0, 3, 73, 1, 255, 2, 153, 1, 197, 2, 0, 24, }; -static const unsigned char _82[] = { +static const unsigned char _82[] PROGMEM = { 0, 22, 197, 1, 255, 4, 0, 2, 197, 1, 36, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 255, 3, 197, 1, 0, 2, 197, 1, 36, 1, 0, 1, 153, 1, 111, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 2, 73, 1, 255, 1, 0, 21, }; -static const unsigned char _83[] = { +static const unsigned char _83[] PROGMEM = { 0, 23, 255, 3, 153, 1, 0, 2, 197, 1, 73, 1, 0, 2, 197, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 5, 73, 1, 255, 2, 73, 1, 0, 6, 153, 1, 255, 1, 73, 1, 0, 5, 36, 1, 197, 1, 0, 1, 255, 1, 73, 1, 0, 2, 111, 1, 153, 1, 0, 1, 36, 1, 255, 3, 197, 1, 0, 22, }; -static const unsigned char _84[] = { +static const unsigned char _84[] PROGMEM = { 0, 18, 197, 1, 255, 5, 0, 2, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 20, }; -static const unsigned char _85[] = { +static const unsigned char _85[] PROGMEM = { 0, 22, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 153, 1, 111, 1, 0, 1, 36, 1, 255, 1, 0, 3, 255, 3, 36, 1, 0, 22, }; -static const unsigned char _86[] = { +static const unsigned char _86[] PROGMEM = { 0, 24, 111, 1, 197, 1, 0, 4, 36, 1, 255, 1, 0, 1, 255, 1, 36, 1, 0, 3, 111, 1, 153, 1, 0, 1, 111, 2, 0, 3, 197, 1, 36, 1, 0, 1, 36, 1, 255, 1, 0, 2, 73, 1, 197, 1, 0, 3, 153, 1, 73, 1, 0, 1, 153, 1, 73, 1, 0, 3, 73, 1, 153, 1, 36, 1, 255, 1, 0, 5, 197, 1, 153, 1, 111, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 26, }; -static const unsigned char _87[] = { +static const unsigned char _87[] PROGMEM = { 0, 30, 73, 1, 153, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 197, 1, 36, 1, 197, 1, 0, 2, 153, 1, 111, 1, 73, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 0, 2, 153, 1, 36, 1, 153, 1, 0, 1, 73, 1, 111, 1, 0, 1, 153, 1, 73, 1, 36, 1, 153, 1, 0, 1, 197, 1, 0, 1, 153, 1, 73, 1, 0, 1, 73, 1, 111, 2, 73, 1, 0, 1, 153, 1, 36, 1, 197, 1, 0, 2, 36, 1, 153, 2, 36, 1, 0, 1, 111, 1, 73, 1, 197, 1, 0, 3, 153, 1, 197, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 3, 153, 2, 0, 3, 255, 1, 73, 1, 0, 31, }; -static const unsigned char _88[] = { +static const unsigned char _88[] PROGMEM = { 0, 21, 36, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 0, 1, 73, 1, 197, 1, 0, 2, 255, 1, 0, 3, 153, 1, 73, 1, 111, 1, 73, 1, 0, 4, 255, 1, 153, 1, 0, 4, 36, 1, 153, 1, 255, 1, 0, 4, 197, 1, 36, 1, 111, 1, 153, 1, 0, 2, 111, 2, 0, 2, 197, 1, 73, 1, 111, 1, 197, 1, 0, 3, 36, 1, 255, 1, 0, 21, }; -static const unsigned char _89[] = { +static const unsigned char _89[] PROGMEM = { 0, 24, 111, 1, 153, 1, 0, 4, 73, 1, 197, 1, 0, 1, 111, 2, 0, 3, 255, 1, 0, 3, 197, 1, 36, 1, 0, 1, 153, 1, 36, 1, 0, 3, 36, 1, 197, 1, 73, 1, 111, 1, 0, 5, 73, 1, 197, 1, 0, 6, 73, 1, 153, 1, 0, 6, 73, 1, 153, 1, 0, 6, 73, 1, 153, 1, 0, 27, }; -static const unsigned char _90[] = { +static const unsigned char _90[] PROGMEM = { 0, 22, 255, 6, 0, 5, 197, 1, 111, 1, 0, 4, 153, 2, 0, 4, 111, 1, 197, 1, 0, 4, 73, 1, 255, 1, 0, 4, 36, 1, 255, 1, 36, 1, 0, 4, 255, 1, 73, 1, 0, 4, 111, 1, 255, 6, 0, 21, }; -static const unsigned char _91[] = { +static const unsigned char _91[] PROGMEM = { 0, 10, 255, 2, 0, 1, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 2, 0, 3, }; -static const unsigned char _93[] = { +static const unsigned char _93[] PROGMEM = { 0, 9, 111, 1, 255, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 111, 1, 255, 1, 153, 1, 0, 3, }; -static const unsigned char _95[] = { +static const unsigned char _95[] PROGMEM = { 0, 72, 197, 1, 255, 5, 0, 6, }; -static const unsigned char _97[] = { +static const unsigned char _97[] PROGMEM = { 0, 31, 36, 1, 255, 3, 0, 2, 197, 1, 36, 1, 0, 1, 153, 1, 73, 1, 0, 2, 197, 1, 255, 2, 111, 1, 0, 1, 255, 1, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 255, 1, 0, 2, 255, 1, 111, 1, 0, 1, 153, 1, 255, 2, 153, 2, 0, 18, }; -static const unsigned char _98[] = { +static const unsigned char _98[] PROGMEM = { 0, 19, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 153, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 73, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 73, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 153, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 153, 1, 255, 2, 0, 19, }; -static const unsigned char _99[] = { +static const unsigned char _99[] PROGMEM = { 0, 32, 197, 1, 255, 2, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 36, 1, 255, 1, 0, 1, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 153, 1, 111, 1, 0, 2, 255, 1, 0, 2, 197, 1, 255, 2, 73, 1, 0, 18, }; -static const unsigned char _100[] = { +static const unsigned char _100[] PROGMEM = { 0, 22, 111, 1, 153, 1, 0, 4, 111, 1, 153, 1, 0, 1, 36, 1, 255, 2, 153, 2, 0, 1, 197, 1, 73, 1, 0, 1, 197, 1, 153, 1, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 73, 1, 0, 1, 153, 2, 0, 1, 36, 1, 255, 2, 197, 1, 153, 1, 0, 18, }; -static const unsigned char _101[] = { +static const unsigned char _101[] PROGMEM = { 0, 32, 255, 3, 0, 2, 197, 1, 36, 1, 0, 1, 73, 1, 153, 1, 0, 1, 255, 4, 197, 1, 0, 1, 255, 1, 0, 5, 197, 1, 111, 1, 0, 1, 111, 1, 153, 1, 0, 2, 255, 3, 0, 19, }; -static const unsigned char _102[] = { +static const unsigned char _102[] PROGMEM = { 0, 14, 111, 1, 255, 1, 0, 2, 197, 1, 36, 1, 0, 1, 153, 1, 255, 2, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 12, }; -static const unsigned char _103[] = { +static const unsigned char _103[] PROGMEM = { 0, 32, 255, 2, 111, 1, 153, 1, 0, 1, 153, 1, 111, 1, 0, 1, 153, 2, 0, 1, 197, 1, 36, 1, 0, 1, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 73, 1, 153, 1, 0, 1, 153, 1, 111, 1, 0, 1, 153, 2, 0, 2, 255, 2, 153, 2, 0, 4, 111, 2, 0, 1, 153, 1, 255, 2, 197, 1, 0, 7, }; -static const unsigned char _104[] = { +static const unsigned char _104[] PROGMEM = { 0, 19, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 111, 1, 0, 1, 153, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 18, }; -static const unsigned char _105[] = { +static const unsigned char _105[] PROGMEM = { 0, 7, 197, 1, 0, 3, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 6, }; -static const unsigned char _106[] = { +static const unsigned char _106[] PROGMEM = { 0, 7, 197, 1, 0, 3, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 255, 2, 0, 2, }; -static const unsigned char _107[] = { +static const unsigned char _107[] PROGMEM = { 0, 16, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 2, 255, 1, 0, 1, 197, 1, 36, 1, 197, 1, 0, 2, 197, 1, 255, 1, 73, 1, 0, 2, 197, 1, 73, 1, 197, 1, 0, 2, 197, 1, 36, 1, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 1, 255, 1, 0, 15, }; -static const unsigned char _108[] = { +static const unsigned char _108[] PROGMEM = { 0, 7, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 6, }; -static const unsigned char _109[] = { +static const unsigned char _109[] PROGMEM = { 0, 41, 197, 1, 153, 1, 255, 1, 197, 1, 111, 1, 255, 1, 197, 1, 0, 1, 197, 1, 111, 1, 0, 1, 197, 1, 111, 1, 0, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 0, 24, }; -static const unsigned char _110[] = { +static const unsigned char _110[] PROGMEM = { 0, 31, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 73, 1, 0, 1, 153, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 18, }; -static const unsigned char _111[] = { +static const unsigned char _111[] PROGMEM = { 0, 31, 36, 1, 255, 2, 197, 1, 0, 2, 197, 1, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 36, 1, 255, 2, 153, 1, 0, 19, }; -static const unsigned char _112[] = { +static const unsigned char _112[] PROGMEM = { 0, 31, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 111, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 111, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 9, }; -static const unsigned char _113[] = { +static const unsigned char _113[] PROGMEM = { 0, 31, 73, 1, 255, 2, 111, 1, 153, 1, 0, 1, 255, 1, 36, 1, 0, 1, 197, 1, 153, 1, 73, 1, 153, 1, 0, 2, 73, 1, 153, 1, 73, 1, 153, 1, 0, 2, 73, 1, 153, 1, 0, 1, 255, 1, 36, 1, 0, 1, 153, 2, 0, 1, 73, 1, 255, 2, 153, 2, 0, 4, 73, 1, 153, 1, 0, 4, 73, 1, 153, 1, 0, 6, }; -static const unsigned char _114[] = { +static const unsigned char _114[] PROGMEM = { 0, 21, 197, 1, 153, 1, 255, 1, 0, 1, 197, 1, 111, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 13, }; -static const unsigned char _115[] = { +static const unsigned char _115[] PROGMEM = { 0, 31, 111, 1, 255, 2, 197, 1, 0, 2, 255, 1, 0, 2, 153, 1, 73, 1, 0, 1, 197, 1, 255, 2, 0, 5, 197, 1, 255, 1, 153, 1, 36, 1, 255, 1, 0, 2, 73, 1, 197, 1, 0, 1, 73, 1, 255, 3, 36, 1, 0, 18, }; -static const unsigned char _116[] = { +static const unsigned char _116[] PROGMEM = { 0, 10, 153, 1, 36, 1, 0, 1, 197, 1, 36, 1, 111, 1, 255, 2, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 153, 1, 255, 1, 0, 9, }; -static const unsigned char _117[] = { +static const unsigned char _117[] PROGMEM = { 0, 31, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 153, 1, 111, 1, 0, 1, 197, 1, 73, 1, 0, 1, 197, 1, 111, 1, 0, 1, 73, 1, 255, 2, 153, 1, 111, 1, 0, 18, }; -static const unsigned char _118[] = { +static const unsigned char _118[] PROGMEM = { 0, 30, 36, 1, 197, 1, 0, 2, 36, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 73, 1, 111, 1, 0, 1, 197, 1, 0, 3, 255, 1, 73, 1, 153, 1, 0, 3, 153, 2, 73, 1, 0, 3, 73, 1, 255, 1, 0, 20, }; -static const unsigned char _119[] = { +static const unsigned char _119[] PROGMEM = { 0, 51, 197, 1, 36, 1, 0, 1, 73, 1, 255, 1, 0, 2, 111, 2, 0, 1, 111, 2, 0, 1, 153, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 73, 1, 111, 1, 36, 1, 197, 1, 0, 3, 197, 1, 73, 1, 153, 1, 0, 1, 197, 1, 111, 2, 0, 3, 111, 1, 197, 1, 73, 1, 0, 1, 197, 1, 153, 1, 36, 1, 0, 3, 36, 1, 255, 1, 36, 1, 0, 1, 111, 1, 197, 1, 0, 32, }; -static const unsigned char _120[] = { +static const unsigned char _120[] PROGMEM = { 0, 30, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 197, 1, 0, 1, 73, 1, 197, 1, 73, 1, 255, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 197, 1, 255, 1, 111, 1, 0, 2, 111, 1, 153, 1, 0, 1, 255, 1, 36, 1, 111, 1, 255, 1, 0, 2, 73, 1, 255, 1, 0, 18, }; -static const unsigned char _121[] = { +static const unsigned char _121[] PROGMEM = { 0, 30, 73, 1, 197, 1, 0, 3, 255, 1, 0, 1, 197, 1, 73, 1, 0, 1, 111, 1, 153, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 2, 255, 1, 36, 1, 197, 1, 0, 3, 153, 1, 197, 1, 73, 1, 0, 3, 36, 1, 255, 1, 0, 4, 111, 2, 0, 3, 255, 2, 0, 9, }; -static const unsigned char _122[] = { +static const unsigned char _122[] PROGMEM = { 0, 31, 153, 1, 255, 3, 197, 1, 0, 4, 153, 1, 36, 1, 0, 3, 153, 1, 73, 1, 0, 3, 111, 2, 0, 3, 73, 1, 153, 1, 0, 4, 255, 4, 197, 1, 0, 18, }; -static const unsigned char _14849714[] = { +static const unsigned char _14849714[] PROGMEM = { 0, 38, 36, 1, 0, 10, 197, 1, 73, 1, 0, 8, 73, 1, 255, 1, 197, 1, 0, 8, 197, 1, 255, 2, 73, 1, 0, 6, 73, 1, 255, 3, 197, 1, 0, 6, 197, 1, 255, 4, 73, 1, 0, 4, 73, 1, 255, 5, 197, 1, 0, 4, 197, 1, 255, 6, 111, 1, 0, 34, }; -static const unsigned char _14849724[] = { +static const unsigned char _14849724[] PROGMEM = { 0, 46, 197, 1, 255, 6, 111, 1, 0, 4, 255, 5, 153, 1, 0, 5, 111, 1, 255, 4, 36, 1, 0, 6, 255, 3, 153, 1, 0, 7, 111, 1, 255, 2, 36, 1, 0, 8, 255, 1, 153, 1, 0, 9, 111, 1, 36, 1, 0, 37, }; static LATTICE lattice_array[] = { {32, 3, _32}, diff --git a/src/tft/Arial_19.cpp b/src/tft/Arial_19.cpp index de5027e5..4b34d767 100644 --- a/src/tft/Arial_19.cpp +++ b/src/tft/Arial_19.cpp @@ -1,176 +1,177 @@ +#include "usb64_conf.h" #include "GuiLite.h" -static const unsigned char _32[] = { +static const unsigned char _32[] PROGMEM = { 0, 95, }; -static const unsigned char _33[] = { +static const unsigned char _33[] PROGMEM = { 0, 17, 255, 1, 197, 1, 0, 3, 255, 1, 197, 1, 0, 3, 255, 1, 197, 1, 0, 3, 255, 1, 197, 1, 0, 3, 255, 1, 197, 1, 0, 3, 197, 1, 153, 1, 0, 3, 197, 1, 153, 1, 0, 3, 153, 1, 111, 1, 0, 3, 153, 1, 111, 1, 0, 3, 153, 1, 111, 1, 0, 8, 255, 1, 197, 1, 0, 21, }; -static const unsigned char _35[] = { +static const unsigned char _35[] PROGMEM = { 0, 30, 111, 2, 0, 2, 153, 1, 73, 1, 0, 3, 153, 1, 73, 1, 0, 2, 197, 1, 36, 1, 0, 3, 255, 1, 0, 2, 36, 1, 197, 1, 0, 3, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 1, 153, 1, 255, 8, 0, 2, 153, 1, 73, 1, 0, 2, 153, 1, 73, 1, 0, 3, 197, 1, 36, 1, 0, 2, 255, 1, 0, 4, 255, 1, 0, 2, 36, 1, 197, 1, 0, 2, 153, 1, 255, 8, 0, 1, 111, 2, 0, 2, 153, 1, 73, 1, 0, 3, 153, 1, 73, 1, 0, 2, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 2, 255, 1, 0, 39, }; -static const unsigned char _37[] = { +static const unsigned char _37[] PROGMEM = { 0, 47, 153, 1, 255, 2, 73, 1, 0, 4, 197, 1, 73, 1, 0, 4, 73, 1, 255, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 2, 73, 1, 153, 1, 0, 5, 153, 1, 197, 1, 0, 2, 197, 1, 111, 1, 0, 2, 197, 1, 36, 1, 0, 5, 153, 2, 0, 2, 197, 1, 153, 1, 0, 1, 111, 2, 0, 6, 153, 2, 0, 2, 197, 1, 111, 1, 0, 1, 255, 1, 0, 7, 73, 1, 255, 1, 0, 1, 36, 1, 255, 1, 36, 1, 111, 2, 0, 1, 255, 3, 36, 1, 0, 3, 153, 1, 255, 2, 73, 1, 0, 1, 255, 1, 0, 1, 153, 1, 197, 1, 0, 1, 111, 1, 255, 1, 0, 7, 153, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 5, 36, 1, 197, 1, 0, 2, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 5, 153, 1, 73, 1, 0, 2, 255, 1, 111, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 4, 73, 1, 153, 1, 0, 3, 153, 1, 197, 1, 0, 1, 111, 1, 197, 1, 0, 5, 197, 1, 36, 1, 0, 4, 197, 1, 255, 2, 36, 1, 0, 61, }; -static const unsigned char _39[] = { +static const unsigned char _39[] PROGMEM = { 0, 10, 255, 1, 153, 1, 0, 1, 255, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 1, 197, 1, 73, 1, 0, 36, }; -static const unsigned char _40[] = { +static const unsigned char _40[] PROGMEM = { 0, 22, 153, 2, 0, 3, 111, 1, 197, 1, 0, 4, 255, 1, 36, 1, 0, 3, 153, 1, 197, 1, 0, 4, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 111, 1, 255, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 4, 255, 1, 111, 1, 0, 4, 153, 1, 197, 1, 0, 5, 255, 1, 73, 1, 0, 4, 111, 1, 197, 1, 0, 5, 153, 2, 0, 6, }; -static const unsigned char _41[] = { +static const unsigned char _41[] PROGMEM = { 0, 19, 111, 1, 197, 1, 0, 5, 153, 2, 0, 4, 36, 1, 255, 1, 36, 1, 0, 4, 153, 1, 197, 1, 0, 4, 73, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 4, 255, 1, 153, 1, 0, 4, 197, 1, 153, 1, 0, 4, 255, 1, 153, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 153, 2, 0, 3, 36, 1, 255, 1, 36, 1, 0, 3, 153, 2, 0, 3, 111, 1, 197, 1, 0, 9, }; -static const unsigned char _43[] = { +static const unsigned char _43[] PROGMEM = { 0, 54, 73, 1, 255, 1, 36, 1, 0, 7, 73, 1, 255, 1, 36, 1, 0, 7, 73, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 7, 111, 1, 0, 4, 73, 1, 255, 1, 36, 1, 0, 7, 73, 1, 255, 1, 36, 1, 0, 7, 73, 1, 255, 1, 36, 1, 0, 73, }; -static const unsigned char _44[] = { +static const unsigned char _44[] PROGMEM = { 0, 72, 255, 1, 153, 1, 0, 3, 36, 1, 153, 1, 0, 3, 111, 2, 0, 3, 197, 1, 0, 7, }; -static const unsigned char _45[] = { +static const unsigned char _45[] PROGMEM = { 0, 60, 36, 1, 255, 4, 197, 1, 0, 48, }; -static const unsigned char _46[] = { +static const unsigned char _46[] PROGMEM = { 0, 72, 255, 1, 153, 1, 0, 21, }; -static const unsigned char _47[] = { +static const unsigned char _47[] PROGMEM = { 0, 19, 255, 1, 0, 3, 73, 1, 153, 1, 0, 3, 153, 1, 73, 1, 0, 3, 255, 1, 0, 3, 73, 1, 153, 1, 0, 3, 153, 1, 111, 1, 0, 3, 197, 1, 36, 1, 0, 2, 36, 1, 197, 1, 0, 3, 111, 2, 0, 3, 197, 1, 36, 1, 0, 2, 36, 1, 197, 1, 0, 3, 111, 2, 0, 23, }; -static const unsigned char _48[] = { +static const unsigned char _48[] PROGMEM = { 0, 30, 255, 4, 0, 4, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 0, 4, 255, 1, 111, 1, 0, 1, 197, 2, 0, 4, 197, 2, 0, 1, 197, 1, 153, 1, 0, 4, 153, 1, 197, 1, 0, 1, 255, 1, 153, 1, 0, 4, 153, 1, 255, 1, 0, 1, 255, 1, 153, 1, 0, 4, 153, 1, 255, 1, 0, 1, 197, 1, 153, 1, 0, 4, 153, 1, 197, 1, 0, 1, 197, 2, 0, 4, 197, 1, 153, 1, 0, 1, 111, 1, 255, 1, 0, 4, 255, 1, 111, 1, 0, 2, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 4, 255, 4, 0, 38, }; -static const unsigned char _49[] = { +static const unsigned char _49[] PROGMEM = { 0, 32, 197, 1, 73, 1, 0, 6, 153, 1, 255, 1, 73, 1, 0, 5, 255, 3, 73, 1, 0, 4, 197, 2, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 38, }; -static const unsigned char _50[] = { +static const unsigned char _50[] PROGMEM = { 0, 29, 36, 1, 255, 4, 0, 3, 36, 1, 255, 1, 197, 1, 0, 2, 255, 2, 0, 2, 153, 1, 255, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 6, 73, 1, 255, 1, 73, 1, 0, 5, 36, 1, 255, 1, 197, 1, 0, 6, 255, 2, 0, 5, 36, 1, 255, 1, 197, 1, 0, 5, 73, 1, 255, 1, 197, 1, 0, 5, 36, 1, 255, 1, 153, 1, 0, 6, 197, 2, 0, 6, 36, 1, 255, 7, 111, 1, 0, 36, }; -static const unsigned char _51[] = { +static const unsigned char _51[] PROGMEM = { 0, 29, 73, 1, 255, 3, 111, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 2, 255, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 0, 7, 111, 1, 255, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 5, 255, 2, 197, 1, 0, 8, 153, 1, 255, 1, 36, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 7, 255, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 111, 1, 255, 1, 0, 3, 153, 1, 197, 1, 0, 3, 73, 1, 255, 3, 197, 1, 0, 38, }; -static const unsigned char _52[] = { +static const unsigned char _52[] PROGMEM = { 0, 32, 73, 1, 255, 1, 36, 1, 0, 6, 255, 2, 36, 1, 0, 5, 153, 1, 255, 2, 36, 1, 0, 4, 36, 1, 255, 1, 111, 1, 255, 1, 36, 1, 0, 4, 197, 1, 111, 1, 73, 1, 255, 1, 36, 1, 0, 3, 111, 1, 197, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 197, 1, 111, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 7, 111, 1, 0, 5, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 37, }; -static const unsigned char _53[] = { +static const unsigned char _53[] PROGMEM = { 0, 29, 153, 1, 255, 5, 0, 3, 255, 1, 111, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 73, 1, 255, 1, 0, 7, 111, 1, 197, 1, 255, 3, 197, 1, 0, 3, 153, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 8, 255, 1, 111, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 111, 1, 255, 1, 0, 3, 111, 1, 197, 1, 0, 3, 73, 1, 255, 3, 153, 1, 0, 38, }; -static const unsigned char _54[] = { +static const unsigned char _54[] PROGMEM = { 0, 30, 255, 4, 0, 4, 255, 1, 36, 1, 0, 2, 197, 1, 255, 1, 0, 2, 153, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 6, 36, 1, 255, 1, 73, 1, 153, 1, 255, 3, 0, 2, 36, 1, 255, 2, 111, 1, 0, 2, 111, 1, 255, 1, 0, 1, 36, 1, 255, 1, 197, 1, 0, 4, 255, 1, 111, 1, 36, 1, 255, 1, 111, 1, 0, 4, 255, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 4, 255, 1, 153, 1, 0, 1, 197, 2, 0, 4, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 111, 1, 197, 1, 0, 4, 255, 3, 197, 1, 0, 38, }; -static const unsigned char _55[] = { +static const unsigned char _55[] PROGMEM = { 0, 28, 197, 1, 255, 6, 153, 1, 0, 6, 153, 1, 255, 1, 36, 1, 0, 5, 73, 1, 255, 1, 111, 1, 0, 6, 197, 2, 0, 6, 73, 1, 255, 1, 73, 1, 0, 6, 153, 1, 255, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 153, 1, 255, 1, 0, 7, 197, 1, 153, 1, 0, 7, 255, 1, 111, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 40, }; -static const unsigned char _56[] = { +static const unsigned char _56[] PROGMEM = { 0, 30, 255, 4, 0, 4, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 2, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 36, 1, 0, 3, 197, 1, 255, 2, 197, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 73, 1, 0, 1, 197, 2, 0, 4, 153, 1, 197, 1, 0, 1, 255, 1, 153, 1, 0, 4, 111, 1, 255, 1, 0, 1, 197, 2, 0, 4, 153, 1, 197, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 4, 36, 1, 0, 37, }; -static const unsigned char _57[] = { +static const unsigned char _57[] PROGMEM = { 0, 29, 36, 1, 255, 3, 111, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 255, 1, 153, 1, 0, 2, 197, 2, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 255, 1, 153, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 197, 2, 0, 3, 73, 1, 255, 1, 153, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 255, 2, 153, 1, 0, 2, 73, 1, 255, 3, 36, 1, 197, 1, 111, 1, 0, 7, 255, 1, 73, 1, 0, 6, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 3, 197, 1, 255, 3, 73, 1, 0, 38, }; -static const unsigned char _58[] = { +static const unsigned char _58[] PROGMEM = { 0, 32, 255, 1, 153, 1, 0, 38, 255, 1, 153, 1, 0, 21, }; -static const unsigned char _59[] = { +static const unsigned char _59[] PROGMEM = { 0, 32, 255, 1, 153, 1, 0, 38, 255, 1, 153, 1, 0, 3, 36, 1, 153, 1, 0, 3, 111, 2, 0, 3, 197, 1, 0, 7, }; -static const unsigned char _60[] = { +static const unsigned char _60[] PROGMEM = { 0, 48, 153, 1, 73, 1, 0, 6, 153, 1, 255, 2, 73, 1, 0, 4, 153, 1, 255, 3, 36, 1, 0, 3, 153, 1, 255, 2, 111, 1, 0, 5, 153, 1, 255, 1, 0, 9, 153, 1, 255, 2, 111, 1, 0, 8, 153, 1, 255, 3, 36, 1, 0, 7, 153, 1, 255, 2, 73, 1, 0, 8, 153, 1, 73, 1, 0, 60, }; -static const unsigned char _61[] = { +static const unsigned char _61[] PROGMEM = { 0, 71, 153, 1, 255, 7, 73, 1, 0, 31, 153, 1, 255, 7, 73, 1, 0, 70, }; -static const unsigned char _62[] = { +static const unsigned char _62[] PROGMEM = { 0, 41, 153, 1, 73, 1, 0, 8, 153, 1, 255, 2, 73, 1, 0, 7, 111, 1, 255, 3, 73, 1, 0, 8, 197, 1, 255, 2, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 5, 197, 1, 255, 2, 73, 1, 0, 3, 111, 1, 255, 3, 73, 1, 0, 4, 153, 1, 255, 2, 73, 1, 0, 6, 153, 1, 73, 1, 0, 67, }; -static const unsigned char _63[] = { +static const unsigned char _63[] PROGMEM = { 0, 29, 36, 1, 255, 4, 0, 3, 36, 1, 255, 1, 111, 1, 0, 2, 197, 1, 255, 1, 0, 2, 153, 1, 197, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 153, 1, 0, 4, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 6, 197, 1, 255, 1, 0, 6, 197, 1, 255, 1, 36, 1, 0, 5, 153, 1, 255, 1, 36, 1, 0, 6, 255, 1, 153, 1, 0, 7, 255, 1, 111, 1, 0, 15, 73, 1, 255, 1, 111, 1, 0, 39, }; -static const unsigned char _64[] = { +static const unsigned char _64[] PROGMEM = { 0, 57, 153, 1, 255, 5, 73, 1, 0, 8, 111, 1, 255, 1, 153, 1, 0, 4, 36, 1, 255, 2, 36, 1, 0, 5, 153, 1, 255, 1, 0, 8, 111, 1, 255, 1, 0, 4, 73, 1, 255, 1, 0, 3, 255, 3, 36, 1, 197, 1, 153, 1, 0, 1, 153, 2, 0, 3, 197, 1, 111, 1, 0, 1, 36, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 2, 111, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 0, 2, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 73, 1, 0, 2, 255, 1, 73, 1, 0, 1, 111, 1, 153, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 2, 197, 1, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 111, 1, 255, 1, 0, 4, 111, 1, 255, 1, 0, 3, 255, 1, 36, 1, 0, 1, 153, 1, 111, 1, 0, 1, 153, 1, 255, 1, 0, 4, 197, 1, 153, 1, 0, 2, 73, 1, 255, 1, 0, 2, 153, 1, 111, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 255, 1, 73, 1, 0, 2, 111, 1, 197, 1, 0, 2, 255, 1, 153, 1, 0, 1, 36, 1, 255, 2, 73, 1, 0, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 2, 197, 1, 0, 1, 255, 3, 73, 1, 0, 5, 197, 1, 153, 1, 0, 10, 36, 1, 255, 1, 111, 1, 0, 3, 255, 1, 153, 1, 0, 9, 255, 1, 153, 1, 0, 5, 255, 2, 111, 1, 0, 5, 153, 1, 255, 1, 153, 1, 0, 8, 197, 1, 255, 5, 153, 1, 0, 4, }; -static const unsigned char _65[] = { +static const unsigned char _65[] PROGMEM = { 0, 37, 73, 1, 255, 2, 0, 8, 197, 1, 153, 1, 255, 1, 111, 1, 0, 6, 36, 1, 255, 1, 73, 1, 197, 2, 0, 6, 153, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 5, 255, 1, 153, 1, 0, 2, 255, 1, 153, 1, 0, 4, 73, 1, 255, 1, 73, 1, 0, 2, 153, 1, 255, 1, 0, 4, 197, 2, 0, 3, 73, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 7, 197, 1, 0, 2, 153, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 255, 1, 153, 1, 0, 5, 36, 1, 255, 1, 153, 1, 73, 1, 255, 1, 73, 1, 0, 6, 153, 1, 255, 1, 197, 2, 0, 7, 73, 1, 255, 1, 0, 44, }; -static const unsigned char _66[] = { +static const unsigned char _66[] PROGMEM = { 0, 34, 73, 1, 255, 6, 153, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 153, 1, 197, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 7, 73, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 197, 1, 255, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 255, 1, 197, 1, 0, 2, 73, 1, 255, 6, 153, 1, 0, 46, }; -static const unsigned char _67[] = { +static const unsigned char _67[] PROGMEM = { 0, 40, 153, 1, 255, 4, 36, 1, 0, 4, 36, 1, 255, 1, 197, 1, 0, 3, 111, 1, 255, 1, 111, 1, 0, 3, 197, 2, 0, 5, 153, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 36, 2, 0, 2, 153, 1, 255, 1, 36, 1, 0, 9, 153, 1, 255, 1, 0, 10, 153, 1, 255, 1, 0, 10, 111, 1, 255, 1, 36, 1, 0, 9, 73, 1, 255, 1, 73, 1, 0, 5, 36, 1, 255, 1, 153, 1, 0, 2, 197, 2, 0, 5, 111, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 197, 1, 0, 3, 111, 1, 255, 1, 111, 1, 0, 5, 197, 1, 255, 4, 36, 1, 0, 50, }; -static const unsigned char _68[] = { +static const unsigned char _68[] PROGMEM = { 0, 37, 73, 1, 255, 6, 197, 1, 0, 4, 73, 1, 255, 1, 73, 1, 0, 4, 197, 1, 255, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 5, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 153, 1, 255, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 5, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 255, 2, 0, 3, 73, 1, 255, 6, 153, 1, 0, 51, }; -static const unsigned char _69[] = { +static const unsigned char _69[] PROGMEM = { 0, 34, 73, 1, 255, 8, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 7, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 8, 111, 1, 0, 44, }; -static const unsigned char _70[] = { +static const unsigned char _70[] PROGMEM = { 0, 31, 73, 1, 255, 7, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 6, 73, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 46, }; -static const unsigned char _71[] = { +static const unsigned char _71[] PROGMEM = { 0, 40, 197, 1, 255, 4, 36, 1, 0, 4, 36, 1, 255, 1, 197, 1, 0, 3, 111, 1, 255, 1, 111, 1, 0, 3, 255, 1, 197, 1, 0, 5, 111, 1, 255, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 5, 36, 1, 153, 1, 36, 1, 0, 1, 153, 1, 255, 1, 0, 10, 197, 2, 0, 10, 197, 2, 0, 3, 73, 1, 255, 4, 111, 1, 0, 1, 153, 1, 255, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 5, 36, 1, 255, 1, 111, 1, 0, 2, 255, 1, 153, 1, 0, 5, 36, 1, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 197, 1, 0, 3, 73, 1, 255, 2, 36, 1, 0, 4, 153, 1, 255, 4, 73, 1, 0, 50, }; -static const unsigned char _72[] = { +static const unsigned char _72[] PROGMEM = { 0, 34, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 8, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 44, }; -static const unsigned char _73[] = { +static const unsigned char _73[] PROGMEM = { 0, 17, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 21, }; -static const unsigned char _74[] = { +static const unsigned char _74[] PROGMEM = { 0, 33, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 2, 255, 1, 111, 1, 0, 3, 197, 2, 0, 2, 255, 1, 153, 1, 0, 3, 197, 1, 153, 1, 0, 2, 111, 1, 255, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 3, 153, 1, 255, 3, 73, 1, 0, 38, }; -static const unsigned char _75[] = { +static const unsigned char _75[] PROGMEM = { 0, 34, 73, 1, 255, 1, 73, 1, 0, 4, 36, 1, 255, 2, 0, 1, 73, 1, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 111, 1, 0, 4, 73, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 5, 73, 1, 255, 1, 73, 1, 255, 2, 197, 1, 0, 5, 73, 1, 255, 2, 111, 2, 255, 1, 153, 1, 0, 4, 73, 1, 255, 1, 153, 1, 0, 2, 197, 1, 255, 1, 73, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 2, 0, 3, 73, 1, 255, 1, 73, 1, 0, 3, 111, 1, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 255, 2, 0, 44, }; -static const unsigned char _76[] = { +static const unsigned char _76[] PROGMEM = { 0, 28, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 6, 197, 1, 0, 36, }; -static const unsigned char _77[] = { +static const unsigned char _77[] PROGMEM = { 0, 40, 153, 1, 255, 1, 197, 1, 0, 5, 36, 1, 255, 2, 0, 2, 153, 1, 255, 2, 36, 1, 0, 4, 73, 1, 255, 2, 0, 2, 153, 1, 255, 1, 153, 1, 73, 1, 0, 4, 153, 2, 255, 1, 0, 2, 153, 1, 255, 1, 73, 1, 153, 1, 0, 4, 255, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 1, 255, 1, 0, 3, 73, 1, 153, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 1, 197, 1, 73, 1, 0, 2, 153, 1, 111, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 1, 111, 1, 153, 1, 0, 2, 255, 1, 36, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 1, 36, 1, 255, 1, 0, 1, 73, 1, 197, 1, 0, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 2, 197, 1, 73, 1, 153, 1, 111, 1, 0, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 2, 153, 1, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 2, 73, 1, 255, 1, 197, 1, 0, 2, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 3, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 0, 53, }; -static const unsigned char _78[] = { +static const unsigned char _78[] PROGMEM = { 0, 34, 111, 1, 255, 1, 111, 1, 0, 4, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 2, 0, 4, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 153, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 1, 153, 2, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 2, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 2, 111, 1, 197, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 255, 1, 73, 2, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 197, 1, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 4, 197, 2, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 4, 73, 1, 255, 2, 36, 1, 0, 1, 111, 1, 255, 1, 0, 5, 153, 1, 255, 1, 36, 1, 0, 44, }; -static const unsigned char _79[] = { +static const unsigned char _79[] PROGMEM = { 0, 40, 255, 4, 153, 1, 0, 5, 73, 1, 255, 1, 153, 1, 0, 3, 255, 2, 0, 4, 255, 1, 153, 1, 0, 5, 255, 1, 153, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 1, 153, 1, 255, 1, 0, 6, 73, 1, 255, 1, 73, 1, 0, 1, 197, 2, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 197, 2, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 153, 1, 255, 1, 0, 6, 73, 1, 255, 1, 73, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 2, 255, 1, 153, 1, 0, 5, 255, 1, 153, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 3, 255, 2, 0, 6, 197, 1, 255, 3, 111, 1, 0, 51, }; -static const unsigned char _80[] = { +static const unsigned char _80[] PROGMEM = { 0, 34, 73, 1, 255, 7, 36, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 36, 1, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 255, 1, 153, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 36, 1, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 197, 1, 255, 1, 0, 2, 73, 1, 255, 7, 0, 3, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 51, }; -static const unsigned char _81[] = { +static const unsigned char _81[] PROGMEM = { 0, 40, 255, 4, 111, 1, 0, 5, 111, 1, 255, 1, 111, 1, 0, 3, 255, 2, 0, 3, 36, 1, 255, 1, 111, 1, 0, 5, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 6, 111, 1, 255, 1, 36, 1, 0, 1, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 153, 1, 255, 1, 0, 6, 111, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 36, 1, 255, 1, 197, 1, 0, 3, 111, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 2, 36, 1, 0, 5, 255, 7, 73, 1, 0, 10, 73, 1, 111, 1, 0, 36, }; -static const unsigned char _82[] = { +static const unsigned char _82[] PROGMEM = { 0, 34, 111, 1, 255, 6, 197, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 111, 1, 255, 6, 153, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 2, 153, 1, 255, 1, 36, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 197, 1, 255, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 1, 73, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 5, 255, 2, 0, 44, }; -static const unsigned char _83[] = { +static const unsigned char _83[] PROGMEM = { 0, 36, 153, 1, 255, 4, 73, 1, 0, 4, 255, 1, 197, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 9, 255, 2, 36, 1, 0, 9, 255, 4, 111, 1, 0, 9, 153, 1, 255, 2, 111, 1, 0, 9, 111, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 6, 255, 1, 111, 1, 0, 1, 153, 1, 255, 1, 0, 5, 36, 1, 255, 1, 73, 1, 0, 2, 255, 2, 36, 1, 0, 3, 255, 1, 197, 1, 0, 4, 153, 1, 255, 4, 111, 1, 0, 46, }; -static const unsigned char _84[] = { +static const unsigned char _84[] PROGMEM = { 0, 27, 255, 9, 0, 4, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 39, }; -static const unsigned char _85[] = { +static const unsigned char _85[] PROGMEM = { 0, 34, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 4, 153, 1, 197, 1, 0, 3, 153, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 111, 1, 255, 4, 36, 1, 0, 46, }; -static const unsigned char _86[] = { +static const unsigned char _86[] PROGMEM = { 0, 33, 111, 1, 255, 1, 73, 1, 0, 6, 111, 1, 255, 1, 0, 1, 255, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 1, 153, 1, 255, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 4, 153, 1, 197, 1, 0, 3, 197, 1, 153, 1, 0, 4, 255, 1, 111, 1, 0, 3, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 2, 153, 2, 0, 5, 153, 2, 0, 1, 36, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 36, 1, 111, 1, 255, 1, 0, 7, 255, 1, 111, 1, 197, 1, 111, 1, 0, 7, 111, 1, 255, 2, 36, 1, 0, 7, 36, 1, 255, 1, 197, 1, 0, 48, }; -static const unsigned char _87[] = { +static const unsigned char _87[] PROGMEM = { 0, 51, 73, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 2, 0, 5, 153, 1, 255, 1, 0, 1, 255, 1, 153, 1, 0, 4, 153, 1, 255, 2, 73, 1, 0, 4, 255, 1, 153, 1, 0, 1, 197, 2, 0, 4, 255, 1, 111, 1, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 73, 1, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 2, 197, 2, 0, 3, 197, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 2, 255, 1, 111, 1, 0, 2, 255, 1, 111, 1, 0, 3, 153, 1, 197, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 153, 1, 197, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 111, 1, 255, 1, 0, 5, 255, 1, 73, 1, 153, 1, 197, 1, 0, 4, 255, 1, 73, 1, 197, 1, 153, 1, 0, 5, 197, 1, 153, 1, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 255, 1, 73, 1, 0, 5, 111, 1, 255, 2, 36, 1, 0, 4, 111, 1, 255, 2, 0, 6, 36, 1, 255, 1, 197, 1, 0, 5, 36, 1, 255, 1, 153, 1, 0, 71, }; -static const unsigned char _88[] = { +static const unsigned char _88[] PROGMEM = { 0, 34, 197, 1, 255, 1, 36, 1, 0, 4, 36, 1, 255, 1, 197, 1, 0, 2, 255, 1, 197, 1, 0, 4, 197, 2, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 1, 36, 2, 255, 1, 73, 1, 0, 6, 197, 1, 153, 1, 197, 1, 153, 1, 0, 7, 36, 1, 255, 1, 197, 1, 0, 8, 111, 1, 255, 2, 73, 1, 0, 6, 73, 1, 255, 1, 73, 1, 153, 1, 255, 1, 36, 1, 0, 5, 255, 1, 153, 1, 0, 2, 255, 1, 197, 1, 0, 4, 197, 1, 255, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 36, 1, 111, 1, 255, 1, 153, 1, 0, 6, 255, 2, 0, 44, }; -static const unsigned char _89[] = { +static const unsigned char _89[] PROGMEM = { 0, 33, 111, 1, 255, 1, 153, 1, 0, 5, 36, 1, 255, 2, 0, 1, 153, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 36, 1, 0, 2, 255, 2, 0, 3, 73, 1, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 153, 1, 0, 2, 197, 2, 0, 5, 153, 1, 255, 1, 36, 1, 111, 1, 255, 1, 36, 1, 0, 6, 255, 3, 111, 1, 0, 7, 73, 1, 255, 1, 197, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 48, }; -static const unsigned char _90[] = { +static const unsigned char _90[] PROGMEM = { 0, 28, 153, 1, 255, 6, 197, 1, 0, 6, 73, 1, 255, 1, 111, 1, 0, 6, 255, 1, 197, 1, 0, 6, 111, 1, 255, 1, 36, 1, 0, 5, 36, 1, 255, 1, 111, 1, 0, 6, 197, 2, 0, 6, 111, 1, 255, 1, 36, 1, 0, 5, 36, 1, 255, 1, 111, 1, 0, 6, 197, 2, 0, 6, 73, 1, 255, 1, 73, 1, 0, 6, 255, 1, 153, 1, 0, 6, 73, 1, 255, 8, 0, 36, }; -static const unsigned char _91[] = { +static const unsigned char _91[] PROGMEM = { 0, 16, 111, 1, 255, 2, 153, 1, 0, 1, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 2, 153, 1, 0, 5, }; -static const unsigned char _93[] = { +static const unsigned char _93[] PROGMEM = { 0, 16, 255, 3, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 255, 3, 36, 1, 0, 5, }; -static const unsigned char _95[] = { +static const unsigned char _95[] PROGMEM = { 0, 153, 197, 1, 255, 8, 0, 9, }; -static const unsigned char _97[] = { +static const unsigned char _97[] PROGMEM = { 0, 56, 73, 1, 255, 4, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 111, 1, 255, 1, 0, 2, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 4, 111, 1, 255, 3, 73, 1, 0, 1, 73, 1, 255, 3, 73, 1, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 3, 111, 1, 255, 1, 73, 1, 0, 1, 197, 1, 255, 1, 0, 2, 36, 1, 255, 2, 73, 1, 0, 2, 255, 4, 36, 1, 255, 1, 111, 1, 0, 36, }; -static const unsigned char _98[] = { +static const unsigned char _98[] PROGMEM = { 0, 28, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 153, 1, 255, 2, 197, 1, 0, 3, 153, 1, 255, 1, 153, 1, 0, 2, 197, 2, 0, 2, 153, 1, 255, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 153, 2, 0, 4, 197, 1, 153, 1, 0, 1, 153, 2, 0, 4, 197, 1, 153, 1, 0, 1, 153, 2, 0, 4, 255, 1, 111, 1, 0, 1, 153, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 153, 1, 255, 1, 111, 1, 0, 2, 197, 2, 0, 2, 153, 3, 255, 2, 197, 1, 0, 38, }; -static const unsigned char _99[] = { +static const unsigned char _99[] PROGMEM = { 0, 56, 36, 1, 255, 3, 111, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 153, 1, 255, 1, 0, 3, 153, 1, 197, 1, 0, 2, 197, 1, 153, 1, 0, 7, 197, 1, 153, 1, 0, 7, 197, 1, 153, 1, 0, 7, 153, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 2, 255, 1, 111, 1, 0, 3, 36, 1, 255, 3, 111, 1, 0, 38, }; -static const unsigned char _100[] = { +static const unsigned char _100[] PROGMEM = { 0, 33, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 3, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 36, 1, 0, 1, 197, 1, 153, 1, 0, 3, 73, 1, 255, 1, 36, 2, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 36, 2, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 36, 2, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 36, 1, 0, 1, 197, 1, 153, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 255, 2, 36, 1, 0, 2, 73, 1, 255, 3, 111, 1, 255, 1, 36, 1, 0, 36, }; -static const unsigned char _101[] = { +static const unsigned char _101[] PROGMEM = { 0, 56, 36, 1, 255, 3, 197, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 2, 197, 2, 0, 2, 197, 2, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 36, 1, 255, 7, 153, 1, 0, 1, 255, 1, 111, 1, 0, 7, 197, 2, 0, 4, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 153, 1, 255, 1, 0, 3, 36, 1, 255, 4, 0, 38, }; -static const unsigned char _102[] = { +static const unsigned char _102[] PROGMEM = { 0, 17, 73, 1, 255, 2, 0, 2, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 1, 73, 1, 255, 4, 0, 2, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 21, }; -static const unsigned char _103[] = { +static const unsigned char _103[] PROGMEM = { 0, 56, 73, 1, 255, 3, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 36, 1, 0, 1, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 36, 2, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 2, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 36, 2, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 36, 1, 0, 2, 73, 1, 255, 3, 111, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 0, 2, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 2, 36, 1, 255, 4, 111, 1, 0, 11, }; -static const unsigned char _104[] = { +static const unsigned char _104[] PROGMEM = { 0, 28, 111, 1, 255, 1, 0, 7, 111, 1, 255, 1, 0, 7, 111, 1, 255, 1, 0, 7, 111, 1, 255, 1, 111, 1, 255, 3, 36, 1, 0, 2, 111, 1, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 36, }; -static const unsigned char _105[] = { +static const unsigned char _105[] PROGMEM = { 0, 13, 73, 1, 255, 1, 36, 1, 0, 9, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 16, }; -static const unsigned char _106[] = { +static const unsigned char _106[] PROGMEM = { 0, 10, 255, 1, 111, 1, 0, 7, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 36, 1, 255, 1, 73, 1, 255, 1, 197, 1, 0, 4, }; -static const unsigned char _107[] = { +static const unsigned char _107[] PROGMEM = { 0, 25, 197, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 2, 73, 1, 255, 1, 197, 1, 0, 1, 197, 1, 153, 1, 0, 2, 255, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 3, 197, 1, 153, 2, 255, 1, 0, 4, 197, 1, 255, 1, 111, 1, 255, 1, 111, 1, 0, 3, 197, 2, 0, 1, 153, 1, 255, 1, 36, 1, 0, 2, 197, 1, 153, 1, 0, 2, 255, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 2, 111, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 197, 1, 255, 1, 0, 32, }; -static const unsigned char _108[] = { +static const unsigned char _108[] PROGMEM = { 0, 10, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 12, }; -static const unsigned char _109[] = { +static const unsigned char _109[] PROGMEM = { 0, 79, 197, 1, 153, 2, 255, 2, 153, 1, 0, 1, 255, 3, 111, 1, 0, 2, 197, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 2, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 1, 197, 2, 0, 3, 255, 1, 153, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 52, }; -static const unsigned char _110[] = { +static const unsigned char _110[] PROGMEM = { 0, 55, 111, 1, 197, 1, 73, 1, 255, 3, 36, 1, 0, 2, 111, 1, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 36, }; -static const unsigned char _111[] = { +static const unsigned char _111[] PROGMEM = { 0, 56, 36, 1, 255, 3, 197, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 197, 2, 0, 2, 197, 2, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 4, 255, 1, 153, 1, 0, 1, 197, 2, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 197, 1, 255, 1, 0, 3, 36, 1, 255, 3, 197, 1, 0, 38, }; -static const unsigned char _112[] = { +static const unsigned char _112[] PROGMEM = { 0, 55, 153, 3, 255, 2, 197, 1, 0, 3, 153, 1, 255, 1, 153, 1, 0, 2, 197, 2, 0, 2, 153, 1, 255, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 153, 2, 0, 4, 255, 1, 111, 1, 0, 1, 153, 2, 0, 4, 255, 1, 153, 1, 0, 1, 153, 2, 0, 4, 255, 1, 111, 1, 0, 1, 153, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 153, 1, 255, 1, 111, 1, 0, 2, 255, 1, 197, 1, 0, 2, 153, 1, 197, 2, 255, 2, 153, 1, 0, 3, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 0, 15, }; -static const unsigned char _113[] = { +static const unsigned char _113[] PROGMEM = { 0, 56, 73, 1, 255, 3, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 73, 1, 36, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 197, 2, 0, 3, 111, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 2, 73, 1, 0, 2, 36, 1, 255, 3, 111, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 9, }; -static const unsigned char _114[] = { +static const unsigned char _114[] PROGMEM = { 0, 37, 73, 1, 255, 1, 111, 1, 255, 2, 0, 1, 73, 1, 255, 1, 197, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 26, }; -static const unsigned char _115[] = { +static const unsigned char _115[] PROGMEM = { 0, 50, 255, 4, 73, 1, 0, 2, 197, 1, 153, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 1, 255, 1, 73, 1, 0, 6, 197, 1, 255, 1, 153, 1, 0, 6, 111, 1, 255, 3, 153, 1, 0, 6, 111, 1, 255, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 4, 111, 1, 0, 33, }; -static const unsigned char _116[] = { +static const unsigned char _116[] PROGMEM = { 0, 13, 36, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 1, 197, 1, 255, 3, 0, 1, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 36, 1, 255, 2, 0, 16, }; -static const unsigned char _117[] = { +static const unsigned char _117[] PROGMEM = { 0, 55, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 2, 255, 2, 36, 1, 0, 2, 111, 1, 255, 3, 36, 1, 255, 1, 36, 1, 0, 36, }; -static const unsigned char _118[] = { +static const unsigned char _118[] PROGMEM = { 0, 42, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 255, 1, 0, 3, 36, 1, 255, 1, 36, 1, 255, 1, 73, 1, 0, 2, 111, 1, 255, 1, 0, 1, 197, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 1, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 73, 1, 153, 1, 197, 1, 0, 3, 197, 1, 153, 1, 255, 1, 111, 1, 0, 3, 73, 1, 255, 2, 36, 1, 0, 4, 255, 1, 197, 1, 0, 30, }; -static const unsigned char _119[] = { +static const unsigned char _119[] PROGMEM = { 0, 66, 111, 1, 255, 1, 0, 3, 255, 1, 197, 1, 0, 2, 73, 1, 255, 1, 36, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 0, 2, 111, 1, 197, 1, 0, 1, 255, 1, 111, 1, 0, 1, 73, 1, 153, 1, 255, 1, 36, 1, 0, 1, 197, 1, 111, 1, 0, 1, 153, 1, 197, 1, 0, 1, 153, 1, 111, 1, 197, 1, 73, 1, 0, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 0, 1, 197, 1, 73, 1, 153, 2, 73, 1, 255, 1, 0, 2, 36, 1, 255, 1, 36, 1, 255, 1, 36, 1, 111, 1, 197, 1, 111, 1, 153, 1, 0, 3, 197, 3, 0, 1, 36, 1, 255, 1, 197, 1, 111, 1, 0, 3, 153, 1, 255, 1, 153, 1, 0, 2, 255, 2, 36, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 197, 1, 255, 1, 0, 46, }; -static const unsigned char _120[] = { +static const unsigned char _120[] PROGMEM = { 0, 42, 36, 1, 255, 1, 111, 1, 0, 2, 153, 1, 197, 1, 0, 1, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 255, 1, 111, 1, 197, 1, 111, 1, 0, 3, 73, 1, 255, 2, 0, 5, 255, 1, 153, 1, 0, 4, 111, 1, 255, 2, 73, 1, 0, 2, 36, 1, 255, 1, 73, 1, 153, 1, 197, 1, 0, 2, 153, 2, 0, 2, 255, 1, 73, 2, 255, 1, 36, 1, 0, 2, 111, 1, 255, 1, 0, 28, }; -static const unsigned char _121[] = { +static const unsigned char _121[] PROGMEM = { 0, 54, 36, 1, 255, 1, 111, 1, 0, 4, 153, 1, 255, 1, 0, 1, 197, 2, 0, 4, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 255, 1, 153, 1, 0, 2, 153, 2, 0, 3, 111, 1, 255, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 73, 1, 111, 1, 197, 1, 0, 5, 197, 1, 153, 1, 197, 1, 111, 1, 0, 5, 73, 1, 255, 2, 36, 1, 0, 6, 255, 1, 153, 1, 0, 7, 255, 1, 73, 1, 0, 6, 111, 1, 197, 1, 0, 5, 153, 1, 255, 2, 0, 14, }; -static const unsigned char _122[] = { +static const unsigned char _122[] PROGMEM = { 0, 49, 255, 6, 153, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 4, 73, 1, 255, 1, 111, 1, 0, 5, 255, 1, 153, 1, 0, 5, 197, 1, 255, 1, 0, 5, 111, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 1, 111, 1, 0, 5, 255, 1, 197, 1, 0, 5, 111, 1, 255, 7, 0, 32, }; -static const unsigned char _14849714[] = { +static const unsigned char _14849714[] PROGMEM = { 0, 59, 36, 1, 0, 16, 197, 1, 73, 1, 0, 14, 73, 1, 255, 1, 197, 1, 0, 14, 197, 1, 255, 2, 73, 1, 0, 12, 73, 1, 255, 3, 197, 1, 0, 12, 197, 1, 255, 4, 73, 1, 0, 10, 73, 1, 255, 5, 197, 1, 0, 10, 197, 1, 255, 6, 73, 1, 0, 8, 73, 1, 255, 7, 197, 1, 0, 8, 197, 1, 255, 8, 73, 1, 0, 6, 73, 1, 255, 9, 197, 1, 0, 6, 255, 11, 111, 1, 0, 70, }; -static const unsigned char _14849724[] = { +static const unsigned char _14849724[] PROGMEM = { 0, 53, 36, 1, 255, 11, 153, 1, 0, 5, 153, 1, 255, 10, 36, 1, 0, 5, 36, 1, 255, 9, 153, 1, 0, 7, 153, 1, 255, 8, 36, 1, 0, 7, 36, 1, 255, 7, 153, 1, 0, 9, 153, 1, 255, 6, 36, 1, 0, 9, 36, 1, 255, 5, 153, 1, 0, 11, 153, 1, 255, 4, 36, 1, 0, 11, 36, 1, 255, 3, 153, 1, 0, 13, 153, 1, 255, 2, 36, 1, 0, 13, 36, 1, 255, 1, 153, 1, 0, 15, 153, 1, 36, 1, 0, 75, }; static LATTICE lattice_array[] = { {32, 5, _32}, From 99fb76ca532efa3ec6595e3c973e4dcf5289f607 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 4 Dec 2021 13:28:16 +1030 Subject: [PATCH 055/121] Input: Store randnet map on ext flash --- src/input.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input.h b/src/input.h index 97db0dc1..bd7052b8 100644 --- a/src/input.h +++ b/src/input.h @@ -13,7 +13,7 @@ typedef struct uint16_t randnet_matrix; } randnet_map_t; -static const randnet_map_t randnet_map[] = { +static const randnet_map_t randnet_map[] PROGMEM = { {HID_KEY_ESCAPE, 0x0A08}, //Escape {HID_KEY_F1, 0x0B01}, // F1 {HID_KEY_F2, 0x0A01}, // F2 From f5f7bb0dd095d7178dbc7d4f1e978f604367e4f6 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 4 Dec 2021 13:28:59 +1030 Subject: [PATCH 056/121] N64: Store constant virtual mempak on ext flash --- src/n64/n64_virtualpak.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/n64/n64_virtualpak.c b/src/n64/n64_virtualpak.c index 292ea082..7143d757 100644 --- a/src/n64/n64_virtualpak.c +++ b/src/n64/n64_virtualpak.c @@ -38,7 +38,7 @@ uint8_t n64_virtualpak_scratch[0x20] = { //First 0x300 bytes of mempak. I took this from a mempak I generated on my n64. //const as the console only needs to read from this area -const uint8_t n64_virtualpak_header[0x300] = { +const uint8_t n64_virtualpak_header[0x300] PROGMEM = { 0x81, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x1A, 0x5F, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, From 5e5f8afa359c67545190e2e54af25f2bd72e06ad Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 7 Dec 2021 07:53:54 +1030 Subject: [PATCH 057/121] Main: Assert rumble pin for HW controller --- .gitmodules | 3 +++ src/lib/tinyalloc | 1 + src/main.cpp | 2 ++ 3 files changed, 6 insertions(+) create mode 160000 src/lib/tinyalloc diff --git a/.gitmodules b/.gitmodules index 9410602c..b87e9f42 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "src/teensy41/ILI9341_t3n"] path = src/port_teensy41/ILI9341_t3n url = https://github.com/KurtE/ILI9341_t3n.git +[submodule "src/lib/tinyalloc"] + path = src/lib/tinyalloc + url = https://github.com/thi-ng/tinyalloc.git diff --git a/src/lib/tinyalloc b/src/lib/tinyalloc new file mode 160000 index 00000000..b60fcd7a --- /dev/null +++ b/src/lib/tinyalloc @@ -0,0 +1 @@ +Subproject commit b60fcd7a351dea8a51f3ec95b19fc0d0d2e4dcd9 diff --git a/src/main.cpp b/src/main.cpp index d911119f..d8750900 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -278,6 +278,8 @@ void loop() input_apply_rumble(c, 0xFF); if (n64_in_dev[c].rpak->state == RUMBLE_STOP) input_apply_rumble(c, 0x00); + if (n64_in_dev[c].rpak->state != RUMBLE_APPLIED && ENABLE_HARDWIRED_CONTROLLER) + n64hal_output_set(HW_RUMBLE, n64_in_dev[c].rpak->state == RUMBLE_START); n64_in_dev[c].rpak->state = RUMBLE_APPLIED; } From ca4d229e5da84ee238f0b6b2ed9391460ef13bcc Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 7 Dec 2021 07:56:17 +1030 Subject: [PATCH 058/121] TFT: Refactor TFT background colour def --- src/tft.cpp | 33 ++++++++++++++++----------------- src/tft.h | 2 ++ 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/tft.cpp b/src/tft.cpp index d01829ad..d7498703 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -31,7 +31,6 @@ extern n64_transferpak n64_tpak[MAX_CONTROLLERS]; static char text_buff[32]; -#define BG_COLOR GL_RGB(16, 20, 16) extern const LATTICE_FONT_INFO Arial_14_GL; extern const LATTICE_FONT_INFO Arial_19_GL; extern c_surface *psurface_guilite; @@ -86,7 +85,7 @@ static const char *n64_peri_to_string(n64_input_dev_t *c) } } -void tft_init() +FLASHMEM void tft_init() { tft_dev_init(); @@ -95,7 +94,7 @@ void tft_init() return; } - psurface_guilite->fill_rect(0, 0, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); + psurface_guilite->fill_rect(0, 0, TFT_WIDTH, TFT_HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); static c_image usb64_image; memset(&usb64_image, 0, sizeof(c_image)); @@ -104,12 +103,12 @@ void tft_init() _image.height = 35; _image.width = 120; _image.pixel_color_array = usb64_logo; - usb64_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 0, BG_COLOR); + usb64_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 0, TFT_BG_COLOR); //Draw RAM status snprintf(text_buff, sizeof(text_buff), "Detected RAM: %uMB", memory_get_ext_ram_size()); extram_size.set_surface(psurface_guilite); - extram_size.set_bg_color(BG_COLOR); + extram_size.set_bg_color(TFT_BG_COLOR); extram_size.set_font_color(GL_RGB(255, 255, 255)); extram_size.set_wnd_pos(125, 0, 1, Arial_14_GL.height); extram_size.set_font_type(&Arial_14_GL); @@ -161,7 +160,7 @@ void tft_force_update() _tft_page_changed = 0; if (_tft_page == 0) { - psurface_guilite->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); + psurface_guilite->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); static c_image controller_image; BITMAP_INFO _image; memset(&controller_image, 0, sizeof(c_image)); @@ -169,14 +168,14 @@ void tft_force_update() _image.height = 45; _image.width = 48; _image.pixel_color_array = controller_icon; - controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 0 / 4), BG_COLOR); - controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 1 / 4), BG_COLOR); - controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 2 / 4), BG_COLOR); - controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 3 / 4), BG_COLOR); + controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 0 / 4), TFT_BG_COLOR); + controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 1 / 4), TFT_BG_COLOR); + controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 2 / 4), TFT_BG_COLOR); + controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 3 / 4), TFT_BG_COLOR); } else if (_tft_page == 1) { - psurface_guilite->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); + psurface_guilite->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); } } @@ -188,7 +187,7 @@ void tft_force_update() { uint32_t colour = input_is_connected(i) ? GL_RGB(0, 255, 0) : GL_RGB(255, 255, 255); controller_status[i].set_surface(psurface_guilite); - controller_status[i].set_bg_color(BG_COLOR); + controller_status[i].set_bg_color(TFT_BG_COLOR); controller_status[i].set_font_color(colour); controller_status[i].set_wnd_pos(50, (45 + 0) + ((TFT_HEIGHT - 45) * i / 4), TFT_WIDTH, Arial_19_GL.height); controller_status[i].set_font_type(&Arial_19_GL); @@ -198,7 +197,7 @@ void tft_force_update() snprintf(text_buff, sizeof(text_buff), "0x%04x/0x%04x", input_get_id_vendor(i), input_get_id_product(i)); controller_id[i].set_surface(psurface_guilite); controller_id[i].set_font_color(colour); - controller_id[i].set_bg_color(BG_COLOR); + controller_id[i].set_bg_color(TFT_BG_COLOR); controller_id[i].set_wnd_pos(50, (45 + 20) + ((TFT_HEIGHT - 45) * i / 4), TFT_WIDTH, Arial_19_GL.height); controller_id[i].set_font_type(&Arial_19_GL); controller_id[i].set_str(text_buff); @@ -207,14 +206,14 @@ void tft_force_update() } else if (_tft_page == 1) { - psurface_guilite->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, BG_COLOR, Z_ORDER_LEVEL_0); + psurface_guilite->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); for (int i = 0; i < _tft_log_max_lines; i++) { if (_tft_log_text_lines[i] == NULL) break; tft_log[i].set_surface(psurface_guilite); - tft_log[i].set_bg_color(BG_COLOR); + tft_log[i].set_bg_color(TFT_BG_COLOR); tft_log[i].set_font_color(GL_RGB(255, 255, 255)); tft_log[i].set_wnd_pos(0, 45 + i * Arial_14_GL.height, TFT_WIDTH, Arial_14_GL.height); tft_log[i].set_font_type(&Arial_14_GL); @@ -237,7 +236,7 @@ void tft_force_update() colour = GL_RGB(0, 255, 0); } n64_status.set_surface(psurface_guilite); - n64_status.set_bg_color(BG_COLOR); + n64_status.set_bg_color(TFT_BG_COLOR); n64_status.set_font_color(colour); n64_status.set_wnd_pos(TFT_WIDTH - (10 * 8), 0, 100, Arial_14_GL.height); n64_status.set_font_type(&Arial_14_GL); @@ -257,7 +256,7 @@ void tft_force_update() colour = GL_RGB(0, 255, 0); } n64_status.set_surface(psurface_guilite); - n64_status.set_bg_color(BG_COLOR); + n64_status.set_bg_color(TFT_BG_COLOR); n64_status.set_font_color(colour); n64_status.set_wnd_pos(125, Arial_14_GL.height, 100, Arial_14_GL.height); n64_status.set_font_type(&Arial_14_GL); diff --git a/src/tft.h b/src/tft.h index 93ec0919..63791969 100644 --- a/src/tft.h +++ b/src/tft.h @@ -4,6 +4,8 @@ #ifndef _TFT_H #define _TFT_H +#define TFT_BG_COLOR GL_RGB(16, 20, 16) + //TFT API void tft_init(); uint8_t tft_change_page(uint8_t page); From c313475a63ba9a4727cb736bb451d703f615872f Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 7 Dec 2021 07:57:45 +1030 Subject: [PATCH 059/121] Ports: Add FLASHMEM define --- src/port_null/usb64_conf.h | 124 +++++++++++++++++++++++++++++++++ src/port_teensy41/usb64_conf.h | 5 ++ 2 files changed, 129 insertions(+) create mode 100644 src/port_null/usb64_conf.h diff --git a/src/port_null/usb64_conf.h b/src/port_null/usb64_conf.h new file mode 100644 index 00000000..0fb802ef --- /dev/null +++ b/src/port_null/usb64_conf.h @@ -0,0 +1,124 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#ifdef ARDUINO +#include +#endif +#include +#include +#include +#include +#include + +#include "printf.h" +#undef printf +#undef sprintf +#undef snprinf +#undef vsnprintf +#undef vprintf + +#ifndef _USB64_CONF_h +#define _USB64_CONF_h + +/* DEBUGGING OUTPUT - WARNING SOME OF THESE MAY BREAK TIMING AND CAUSE ISSUES + USE ONLY FOR DEBUGGING */ +#define serial_port Serial1 +#define DEBUG_STATUS 1 //General information +#define DEBUG_N64 0 //For debugging N64 low level info +#define DEBUG_TPAK 0 //For debugging N64 TPAK low level info. It's complex so has its own flag +#define DEBUG_USBHOST 0 //For debugging the USB Host Stack +#define DEBUG_FATFS 0 //For debugging the FATFS io +#define DEBUG_MEMORY 0 //For debugging the memory allocator in external RAM. +#define DEBUG_ERROR 1 //For showing critical errors + +/* USB HOST STACK */ +#define ENABLE_USB_HUB 1 + +/* N64 LIB */ +#define MAX_CONTROLLERS 4 //Max is 4 +#define MAX_MICE 4 //0 to disable N64 mouse support. Must be <= MAX_CONTROLLERS +#define MAX_KB 4 //0 to disable N64 randnet keyboard support. Must be <= MAX_CONTROLLERS +#define MAX_GBROMS 10 //ROMS over this will just get ignored +#define ENABLE_I2C_CONTROLLERS 0 //Received button presses over I2C, useful for integrating with a rasp pi etc. +#define ENABLE_HARDWIRED_CONTROLLER 1 //Ability to hardware a N64 controller into the usb64. +#define PERI_CHANGE_TIME 750 //Milliseconds to simulate a peripheral changing time. Needed for some games. + +/* PIN MAPPING */ +#define N64_CONSOLE_SENSE 37 +#define N64_CONTROLLER_1_PIN 36 +#define N64_CONTROLLER_2_PIN 35 +#define N64_CONTROLLER_3_PIN 34 +#define N64_CONTROLLER_4_PIN 33 +#define N64_FRAME 23 //Pulses high each time N64 console requests input. Presumably related to frames. +#define USER_LED_PIN 13 + +//Hardwired interface. All digital inputs are pulled up, active low. +#define HW_A 2 +#define HW_B 3 +#define HW_CU 4 +#define HW_CD 5 +#define HW_CL 6 +#define HW_CR 7 +#define HW_DU 8 +#define HW_DD 9 +#define HW_DL 10 +#define HW_DR 11 +#define HW_START 12 +#define HW_Z 28 +#define HW_R 29 +#define HW_L 30 +#define HW_RUMBLE 31 //Output, 1 when should be rumbling +#define HW_EN 32 //Active low, pulled high +#define HW_X 24 //Analog input, 0V to VCC. VCC/2 centre +#define HW_Y 25 //Analog input, 0V to VCC. VCC/2 centre + +/* FILESYSTEM */ +#define MAX_FILENAME_LEN 256 +#define SETTINGS_FILENAME "SETTINGS.DAT" +#define GAMEBOY_SAVE_EXT ".SAV" //ROMFILENAME.SAV +#define MEMPAK_SAVE_EXT ".MPK" //MEMPAKXX.MPK + +/* FIRMWARE DEFAULTS (CONFIGURABLE DURING USE) */ +#define DEFAULT_SENSITIVITY 2 //0 to 4 (0 = low sensitivity, 4 = max) +#define DEFAULT_DEADZONE 2 //0 to 4 (0 = no deadzone correction, 4 = max (40%)) +#define DEFAULT_SNAP 1 //0 or 1 (0 = will output raw analog stick angle, 1 will snap to 45deg angles) +#define DEFAULT_OCTA_CORRECT 1 //0 or 1 (Will correct the circular analog stuck shape to N64 octagonal) + +/* FIRMWARE DEFAULTS (NOT CONFIGURABLE DURING USE) */ +#define SNAP_RANGE 5 //+/- what angle range will snap. 5 will snap to 45 degree if between 40 and 50 degrees. +#define MOUSE_SENSITIVITY 2.0f //Just what felt right to me with my mouse. +#define MAG_AT_45DEG 1.1f //Octagonal shape has a larger magnitude at the 45degree points. 1.1 times larger seems about right + +/* TFT DISPLAY */ +#define ENABLE_TFT_DISPLAY 1 +#define TFT_ROTATION 1 //0-3 +#define TFT_DC 40 +#define TFT_CS 41 +#define TFT_MOSI 26 +#define TFT_SCK 27 +#define TFT_MISO 39 +#define TFT_RST 255 +#define TFT_WIDTH 320 +#define TFT_HEIGHT 240 +#define TFT_PIXEL_SIZE 2 +#define TFT_USE_FRAMEBUFFER 1 + +/* Optional, to save RAM, define for variables to store in flash only */ +#ifndef PROGMEM +#define PROGMEM +#endif +/* Optional, to save RAM, define for function to store in flash only */ +#ifndef FLASHMEM +#define FLASHMEM +#endif + +/* DEBUG PRINTERS */ +#define debug_print_status(fmt, ...) do { if (DEBUG_STATUS) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_n64(fmt, ...) do { if (DEBUG_N64) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_tpak(fmt, ...) do { if (DEBUG_TPAK) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_usbhost(fmt, ...) do { if (DEBUG_USBHOST) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_fatfs(fmt, ...) do { if (DEBUG_FATFS) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_memory(fmt, ...) do { if (DEBUG_MEMORY) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_error(fmt, ...) do { if (DEBUG_ERROR) usb64_printf(fmt, ##__VA_ARGS__); } while (0) + +#endif \ No newline at end of file diff --git a/src/port_teensy41/usb64_conf.h b/src/port_teensy41/usb64_conf.h index add67af9..ef355682 100644 --- a/src/port_teensy41/usb64_conf.h +++ b/src/port_teensy41/usb64_conf.h @@ -107,6 +107,11 @@ #ifndef PROGMEM #define PROGMEM #endif +/* Define for function to store in flash only */ +#ifndef FLASHMEM +#define FLASHMEM +#endif + /* DEBUG PRINTERS */ #define debug_print_status(fmt, ...) do { if (DEBUG_STATUS) usb64_printf(fmt, ##__VA_ARGS__); } while (0) From 152ca04512a21c27642e9b2b690a3b3876584b97 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 7 Dec 2021 07:59:51 +1030 Subject: [PATCH 060/121] usb64: Make init functions execute from flash where possible --- src/fileio.cpp | 2 +- src/input.cpp | 2 +- src/memory.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fileio.cpp b/src/fileio.cpp index b150d66f..9976ce93 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -7,7 +7,7 @@ static bool fileio_ok = false; -void fileio_init() +FLASHMEM void fileio_init() { if (!fileio_dev_init()) { diff --git a/src/input.cpp b/src/input.cpp index 0864f3e1..3382ba72 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -84,7 +84,7 @@ static int _check_id(uint8_t id) return 1; } -void input_init() +FLASHMEM void input_init() { tusb_init(); memset(input_devices, 0x00, sizeof(input_devices)); diff --git a/src/memory.cpp b/src/memory.cpp index 5ae2b215..f627a738 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -19,7 +19,7 @@ static sram_storage sram[32] = {0}; -void memory_init() +FLASHMEM void memory_init() { if (!memory_dev_init()) { @@ -82,7 +82,7 @@ uint8_t *memory_alloc_ram(const char *name, uint32_t alloc_len, uint32_t read_on sram[i].read_only = read_only; sram[i].dirty = 0; - debug_print_memory("[MEMORY] Alloc'd %s, %u bytes at 0x%llx\n", sram[i].name, sram[i].len, (uintptr_t)sram[i].data); + debug_print_memory("[MEMORY] Alloc'd %s, %u bytes at 0x%x\n", sram[i].name, sram[i].len, (uintptr_t)sram[i].data); return sram[i].data; } } From 11a174ec7d15ba20411f7800d8e2032230ff60fe Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 7 Dec 2021 08:49:50 +1030 Subject: [PATCH 061/121] N64: Bracket calc to prevent overflow --- src/n64/n64_controller.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/n64/n64_controller.c b/src/n64/n64_controller.c index 9f690e6d..d50bda05 100644 --- a/src/n64/n64_controller.c +++ b/src/n64/n64_controller.c @@ -161,7 +161,7 @@ void n64_controller_hande_new_edge(n64_input_dev_t *cont) uint32_t start_clock = n64hal_hs_tick_get(); //If bus has been idle for 300us, start of a new stream. - if ((n64hal_hs_tick_get() - cont->bus_idle_timer_clks) > (300 * n64hal_hs_tick_get_speed() / 1000000)) + if ((n64hal_hs_tick_get() - cont->bus_idle_timer_clks) > (300 * (n64hal_hs_tick_get_speed() / 1000000))) { n64_reset_stream(cont); cont->peri_access = 0; From 421c798c4a2f9fb914515637df59e5ae8890cb9c Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 7 Dec 2021 13:33:34 +1030 Subject: [PATCH 062/121] usb64: Refactor GPIO for better portability --- src/main.cpp | 84 ++++------------------------------------ src/n64/n64_controller.c | 18 +++++---- src/n64/n64_controller.h | 2 +- src/n64_wrapper.h | 15 +++---- src/tft.cpp | 2 +- 5 files changed, 28 insertions(+), 93 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d8750900..3969b6c6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,25 +46,6 @@ void n64_controller4_clock_edge() } #endif -#ifdef __IMXRT1062__ -extern "C" { -FLASHMEM void startup_early_hook(void) -{ - //Get these up as early as possible. - n64hal_pin_set_mode(N64_CONTROLLER_1_PIN, N64_INPUT_PULLUP); - n64hal_pin_set_mode(N64_CONTROLLER_2_PIN, N64_INPUT_PULLUP); - n64hal_pin_set_mode(N64_CONTROLLER_3_PIN, N64_INPUT_PULLUP); - n64hal_pin_set_mode(N64_CONTROLLER_4_PIN, N64_INPUT_PULLUP); - n64hal_pin_set_mode(N64_CONSOLE_SENSE, N64_INPUT_PULLDOWN); -} -} -#else -void startup_early_hook(void) -{ - -} -#endif - #ifdef CFG_TUSB_DEBUG_PRINTF extern "C" int CFG_TUSB_DEBUG_PRINTF(const char *format, ...) { @@ -78,13 +59,8 @@ extern "C" int CFG_TUSB_DEBUG_PRINTF(const char *format, ...) #ifndef ARDUINO void setup(); void loop(); -#include -#include -#include -#include int main(void) { - startup_early_hook(); setup(); while(1) { @@ -95,9 +71,9 @@ int main(void) void setup() { - //Init the serial port and ring buffer n64hal_system_init(); n64hal_debug_init(); + n64hal_gpio_init(); ring_buffer_init(); fileio_init(); memory_init(); @@ -109,52 +85,6 @@ void setup() //Read in settings from flash settings = (n64_settings *)memory_alloc_ram(SETTINGS_FILENAME, sizeof(n64_settings), MEMORY_READ_WRITE); n64_settings_init(settings); - - //Set up N64 sense pin. To determine is the N64 is turned on or off - //Input is connected to the N64 3V3 line on the controller port. - n64hal_pin_set_mode(N64_CONSOLE_SENSE, N64_INPUT_PULLDOWN); - n64hal_pin_set_mode(N64_FRAME, N64_OUTPUT); - n64hal_pin_set_mode(USER_LED_PIN, N64_OUTPUT); - -#if (ENABLE_HARDWIRED_CONTROLLER >=1) - n64hal_pin_set_mode(HW_A, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_B, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_CU, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_CD, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_CL, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_CR, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_DU, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_DD, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_DL, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_DR, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_START, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_Z, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_R, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_L, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_EN, N64_INPUT_PULLUP); - n64hal_pin_set_mode(HW_RUMBLE, N64_OUTPUT); -#endif - -#if (MAX_CONTROLLERS >= 1) - n64_in_dev[0].gpio_pin = N64_CONTROLLER_1_PIN; - n64hal_pin_set_mode(N64_CONTROLLER_1_PIN, N64_INPUT_PULLUP); -#endif - -#if (MAX_CONTROLLERS >= 2) - n64_in_dev[1].gpio_pin = N64_CONTROLLER_2_PIN; - n64hal_pin_set_mode(N64_CONTROLLER_2_PIN, N64_INPUT_PULLUP); -#endif - -#if (MAX_CONTROLLERS >= 3) - n64_in_dev[2].gpio_pin = N64_CONTROLLER_3_PIN; - n64hal_pin_set_mode(N64_CONTROLLER_3_PIN, N64_INPUT_PULLUP); -#endif - -#if (MAX_CONTROLLERS >= 4) - n64_in_dev[3].gpio_pin = N64_CONTROLLER_4_PIN; - n64hal_pin_set_mode(N64_CONTROLLER_4_PIN, N64_INPUT_PULLUP); -#endif - n64hal_output_set(USER_LED_PIN, 1); } static bool n64_combo = false; @@ -176,10 +106,10 @@ void loop() { switch (c) { - case 0: n64hal_attach_interrupt(n64_in_dev[c].gpio_pin, n64_controller1_clock_edge, N64_INTMODE_FALLING); break; - case 1: n64hal_attach_interrupt(n64_in_dev[c].gpio_pin, n64_controller2_clock_edge, N64_INTMODE_FALLING); break; - case 2: n64hal_attach_interrupt(n64_in_dev[c].gpio_pin, n64_controller3_clock_edge, N64_INTMODE_FALLING); break; - case 3: n64hal_attach_interrupt(n64_in_dev[c].gpio_pin, n64_controller4_clock_edge, N64_INTMODE_FALLING); break; + case 0: n64hal_attach_interrupt(n64_in_dev[c].pin, n64_controller1_clock_edge, N64_INTMODE_FALLING); break; + case 1: n64hal_attach_interrupt(n64_in_dev[c].pin, n64_controller2_clock_edge, N64_INTMODE_FALLING); break; + case 2: n64hal_attach_interrupt(n64_in_dev[c].pin, n64_controller3_clock_edge, N64_INTMODE_FALLING); break; + case 3: n64hal_attach_interrupt(n64_in_dev[c].pin, n64_controller4_clock_edge, N64_INTMODE_FALLING); break; } n64_in_dev[c].interrupt_attached = true; } @@ -260,7 +190,7 @@ void loop() if ((!input_is_connected(c) || !n64_is_on) && n64_in_dev[c].interrupt_attached) { n64_in_dev[c].interrupt_attached = false; - n64hal_detach_interrupt(n64_in_dev[c].gpio_pin); + n64hal_detach_interrupt(n64_in_dev[c].pin); } //Get a copy of the latest n64 button presses to handle the below combos @@ -301,7 +231,7 @@ void loop() //Handle ram flushing. Auto flushes when the N64 is turned off :) static uint32_t flushing_toggle[MAX_CONTROLLERS] = {0}; - n64_is_on = n64hal_input_read(N64_CONSOLE_SENSE); + n64_is_on = n64hal_input_read(N64_CONSOLE_SENSE_PIN); if ((n64_combo && (n64_buttons & N64_A)) || (n64_is_on == 0)) { if (flushing_toggle[c] == 0) diff --git a/src/n64/n64_controller.c b/src/n64/n64_controller.c index d50bda05..1f1750ec 100644 --- a/src/n64/n64_controller.c +++ b/src/n64/n64_controller.c @@ -46,6 +46,10 @@ void n64_subsystem_init(n64_input_dev_t *in_dev) in_dev[i].interrupt_attached = false; in_dev[i].peri_access = 0; in_dev[i].type = N64_CONTROLLER; + in_dev[i].pin = (i == 0) ? N64_CONTROLLER_1_PIN : + (i == 1) ? N64_CONTROLLER_2_PIN : + (i == 2) ? N64_CONTROLLER_3_PIN : + (i == 3) ? N64_CONTROLLER_4_PIN : -1; } //Setup the Controller pin IO mapping and interrupts @@ -118,10 +122,10 @@ static void n64_send_stream(uint8_t *txbuff, uint32_t len, n64_input_dev_t *c) while (len > 0) { while ((n64hal_hs_tick_get() - cycle_start) < cycle_cnt); - n64hal_input_swap(c, N64_OUTPUT); //OUTPUT_PP will pull low + n64hal_input_swap(c->pin, N64_OUTPUT); //OUTPUT_PP will pull low (txbuff[current_byte] & 0x80) ? (cycle_cnt += 1 * U_SEC) : (cycle_cnt += 3 * U_SEC); while ((n64hal_hs_tick_get() - cycle_start) < cycle_cnt); - n64hal_input_swap(c, N64_INPUT); + n64hal_input_swap(c->pin, N64_INPUT); (txbuff[current_byte] & 0x80) ? (cycle_cnt += 3 * U_SEC) : (cycle_cnt += 1 * U_SEC); txbuff[current_byte] = txbuff[current_byte] << 1; current_bit--; @@ -137,10 +141,10 @@ static void n64_send_stream(uint8_t *txbuff, uint32_t len, n64_input_dev_t *c) //Send stop bit. Pull low for 2us, then release. while ((n64hal_hs_tick_get() - cycle_start) < cycle_cnt); - n64hal_input_swap(c, N64_OUTPUT); + n64hal_input_swap(c->pin, N64_OUTPUT); cycle_cnt += 2 * U_SEC; while ((n64hal_hs_tick_get() - cycle_start) < cycle_cnt); - n64hal_input_swap(c, N64_INPUT); //Release bus. We're done + n64hal_input_swap(c->pin, N64_INPUT); //Release bus. We're done } static void n64_reset_stream(n64_input_dev_t *cont) @@ -181,7 +185,7 @@ void n64_controller_hande_new_edge(n64_input_dev_t *cont) while (n64hal_hs_tick_get() < sample_clock); //Read bit - cont->data_buffer[cont->current_byte] |= n64hal_input_read(cont->gpio_pin) << cont->current_bit; + cont->data_buffer[cont->current_byte] |= n64hal_input_read(cont->pin) << cont->current_bit; cont->current_bit -= 1; //Reset idle timer @@ -218,12 +222,12 @@ void n64_controller_hande_new_edge(n64_input_dev_t *cont) case N64_CONTROLLER_STATUS: if (cont->type == N64_RANDNET) //Randnet does not response to this break; - n64hal_output_set(N64_FRAME, 1); + n64hal_output_set(N64_FRAME_PIN, 1); n64_wait_micros(2); n64_send_stream((uint8_t *)&cont->b_state, 4, cont); n64_reset_stream(cont); cont->b_state.dButtons = 0x0000; - n64hal_output_set(N64_FRAME, 0); + n64hal_output_set(N64_FRAME_PIN, 0); break; case N64_RANDNET_REQ: break; diff --git a/src/n64/n64_controller.h b/src/n64/n64_controller.h index 6f152885..e6118d09 100644 --- a/src/n64/n64_controller.h +++ b/src/n64/n64_controller.h @@ -61,7 +61,7 @@ typedef struct // uint32_t interrupt_attached; //Flag is set when this controller is connected to an ext int. uint32_t bus_idle_timer_clks; //Timer counter for bus idle timing - uint32_t gpio_pin; //What pin is this controller connected to + usb64_pin_t pin; //What pin is this controller connected to } n64_input_dev_t; //N64 JOYBUS diff --git a/src/n64_wrapper.h b/src/n64_wrapper.h index 143678ff..a462393d 100644 --- a/src/n64_wrapper.h +++ b/src/n64_wrapper.h @@ -24,8 +24,8 @@ extern "C" { void n64hal_system_init(); void n64hal_debug_init(); void n64hal_debug_write(char c); -void n64hal_attach_interrupt(uint8_t pin, void (*handler)(void), int mode); -void n64hal_detach_interrupt(uint8_t pin); +void n64hal_attach_interrupt(usb64_pin_t pin, void (*handler)(void), int mode); +void n64hal_detach_interrupt(usb64_pin_t pin); void n64hal_disable_interrupts(); void n64hal_enable_interrupts(); @@ -38,16 +38,17 @@ uint32_t n64hal_hs_tick_get_speed(); void n64hal_hs_tick_init(); uint32_t n64hal_hs_tick_get(); uint32_t n64hal_millis(); - + //RAM access wrappers void n64hal_read_extram(void *rx_buff, void *src, uint32_t offset, uint32_t len); void n64hal_write_extram(void *tx_buff, void *dst, uint32_t offset, uint32_t len); //GPIO wrappers -void n64hal_output_set(uint8_t pin, uint8_t level); -void n64hal_input_swap(n64_input_dev_t *controller, uint8_t val); -uint8_t n64hal_input_read(int pin); -void n64hal_pin_set_mode(int pin, uint8_t mode); +void n64hal_gpio_init(); +dev_gpio_t *n64hal_pin_to_gpio(usb64_pin_t pin); +void n64hal_output_set(usb64_pin_t pin, uint8_t level); +void n64hal_input_swap(usb64_pin_t pin, uint8_t val); +uint8_t n64hal_input_read(usb64_pin_t pin); //FileIO wrappers uint32_t n64hal_list_gb_roms(char **list, uint32_t max); diff --git a/src/tft.cpp b/src/tft.cpp index d7498703..0f67ddc1 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -225,7 +225,7 @@ void tft_force_update() //Draw N64 console status uint32_t colour; const char *n64_status_text; - if (n64hal_input_read(N64_CONSOLE_SENSE) == 0) + if (n64hal_input_read(N64_CONSOLE_SENSE_PIN) == 0) { n64_status_text = "N64 is OFF"; colour = GL_RGB(255, 0, 0); From 6281b4876d44c4913615c316f61801339e26b323 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 7 Dec 2021 13:34:47 +1030 Subject: [PATCH 063/121] null: Update backend for GPIO refactor --- src/port_null/hal_null.cpp | 42 +++++++++++++++++++------------- src/port_null/usb64_conf.h | 49 +++++++++++++------------------------- 2 files changed, 41 insertions(+), 50 deletions(-) diff --git a/src/port_null/hal_null.cpp b/src/port_null/hal_null.cpp index 7f31ee3e..de5750a2 100644 --- a/src/port_null/hal_null.cpp +++ b/src/port_null/hal_null.cpp @@ -27,6 +27,16 @@ void n64hal_debug_init() { } +/* + * Function: Initialse the device GPIO for all pins set in usb64_conf.h + * Note, n64 controller pins must be input pullup wth falling edge interrupt enabled. + * ---------------------------- + * Returns: void + */ +void n64hal_gpio_init() +{ +} + /* * Function: Write a character to a debug output (i.e UART etc) * ---------------------------- @@ -63,7 +73,7 @@ void n64hal_enable_interrupts() * handler: Interrupt handler function in the form `void my_int_handler(void)` * mode: N64_INTMODE_FALLING or N64_INTMODE_CHANGE or N64_INTMODE_RISING */ -void n64hal_attach_interrupt(uint8_t pin, void (*handler)(void), int mode) +void n64hal_attach_interrupt(usb64_pin_t pin, void (*handler)(void), int mode) { } @@ -74,7 +84,7 @@ void n64hal_attach_interrupt(uint8_t pin, void (*handler)(void), int mode) * * pin: The pin the configure (See usb64_conf.h) */ -void n64hal_detach_interrupt(uint8_t pin) +void n64hal_detach_interrupt(usb64_pin_t pin) { } @@ -159,6 +169,16 @@ uint32_t n64hal_millis() return 0; } +/* + * Function: Converts a usb64_pin_t enum (See usb64_config.h) into your device specifc gpio structure + * ---------------------------- + * Returns: Pointer to the dev_gpio_t struct defined in usb64_conf.h + */ +dev_gpio_t *n64hal_pin_to_gpio(usb64_pin_t pin) +{ + return NULL; +} + /* * Function: Flips the gpio pin direction from an output (driven low) to an input (pulled up) * for the controller passed by controller. @@ -169,7 +189,7 @@ uint32_t n64hal_millis() * controller: Pointer to the n64 controller struct which contains the gpio mapping * val: N64_OUTPUT or N64_INPUT */ -void n64hal_input_swap(n64_input_dev_t *controller, uint8_t val) +void n64hal_input_swap(usb64_pin_t pin, uint8_t val) { } @@ -181,23 +201,11 @@ void n64hal_input_swap(n64_input_dev_t *controller, uint8_t val) * * pin: The pin the configure (See usb64_conf.h) */ -uint8_t n64hal_input_read(int pin) +uint8_t n64hal_input_read(usb64_pin_t pin) { return 0; } -/* - * Function: Sets the GPIO mode of a pin - * ---------------------------- - * Returns: void - * - * pin: The pin the configure (See usb64_conf.h) - * val: N64_OUTPUT or N64_INPUT_PULLDOWN or N64_INPUT_PULLUP - */ -void n64hal_pin_set_mode(int pin, uint8_t mode) -{ -} - /* * Function: Sets an output GPI to a level * Speed critical! @@ -207,7 +215,7 @@ void n64hal_pin_set_mode(int pin, uint8_t mode) * pin: The pin the configure (See usb64_conf.h) * level: 1 or 0 */ -void n64hal_output_set(uint8_t pin, uint8_t level) +void n64hal_output_set(usb64_pin_t pin, uint8_t level) { } diff --git a/src/port_null/usb64_conf.h b/src/port_null/usb64_conf.h index 0fb802ef..71c34da7 100644 --- a/src/port_null/usb64_conf.h +++ b/src/port_null/usb64_conf.h @@ -43,34 +43,23 @@ #define ENABLE_HARDWIRED_CONTROLLER 1 //Ability to hardware a N64 controller into the usb64. #define PERI_CHANGE_TIME 750 //Milliseconds to simulate a peripheral changing time. Needed for some games. -/* PIN MAPPING */ -#define N64_CONSOLE_SENSE 37 -#define N64_CONTROLLER_1_PIN 36 -#define N64_CONTROLLER_2_PIN 35 -#define N64_CONTROLLER_3_PIN 34 -#define N64_CONTROLLER_4_PIN 33 -#define N64_FRAME 23 //Pulses high each time N64 console requests input. Presumably related to frames. -#define USER_LED_PIN 13 +typedef struct +{ + int pin; +} dev_gpio_t; -//Hardwired interface. All digital inputs are pulled up, active low. -#define HW_A 2 -#define HW_B 3 -#define HW_CU 4 -#define HW_CD 5 -#define HW_CL 6 -#define HW_CR 7 -#define HW_DU 8 -#define HW_DD 9 -#define HW_DL 10 -#define HW_DR 11 -#define HW_START 12 -#define HW_Z 28 -#define HW_R 29 -#define HW_L 30 -#define HW_RUMBLE 31 //Output, 1 when should be rumbling -#define HW_EN 32 //Active low, pulled high -#define HW_X 24 //Analog input, 0V to VCC. VCC/2 centre -#define HW_Y 25 //Analog input, 0V to VCC. VCC/2 centre +/* PIN MAPPING */ +typedef enum { + USER_LED_PIN, + N64_FRAME_PIN, + HW_RUMBLE, + N64_CONSOLE_SENSE_PIN, + N64_CONTROLLER_1_PIN, + N64_CONTROLLER_2_PIN, + N64_CONTROLLER_3_PIN, + N64_CONTROLLER_4_PIN, + USB64_PIN_MAX, +} usb64_pin_t; /* FILESYSTEM */ #define MAX_FILENAME_LEN 256 @@ -92,12 +81,6 @@ /* TFT DISPLAY */ #define ENABLE_TFT_DISPLAY 1 #define TFT_ROTATION 1 //0-3 -#define TFT_DC 40 -#define TFT_CS 41 -#define TFT_MOSI 26 -#define TFT_SCK 27 -#define TFT_MISO 39 -#define TFT_RST 255 #define TFT_WIDTH 320 #define TFT_HEIGHT 240 #define TFT_PIXEL_SIZE 2 From 921ff7efacc4b55711a6aad58bee93e5fcf63137 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 7 Dec 2021 13:35:40 +1030 Subject: [PATCH 064/121] t4: Update backend for GPIO refactor --- src/port_teensy41/hal_t4.cpp | 99 ++++++++++++++++++++++------------ src/port_teensy41/usb64_conf.h | 76 ++++++++++++++------------ 2 files changed, 106 insertions(+), 69 deletions(-) diff --git a/src/port_teensy41/hal_t4.cpp b/src/port_teensy41/hal_t4.cpp index 052d2ed9..50171bf2 100644 --- a/src/port_teensy41/hal_t4.cpp +++ b/src/port_teensy41/hal_t4.cpp @@ -19,6 +19,48 @@ void n64hal_debug_init() serial_port.begin(256000); } +void n64hal_gpio_init() +{ + pinMode(N64_CONTROLLER_1_PIN, INPUT_PULLUP); + pinMode(N64_CONTROLLER_2_PIN, INPUT_PULLUP); + pinMode(N64_CONTROLLER_3_PIN, INPUT_PULLUP); + pinMode(N64_CONTROLLER_4_PIN, INPUT_PULLUP); + pinMode(N64_CONSOLE_SENSE_PIN, INPUT_PULLDOWN); + + //Set up N64 sense pin. To determine is the N64 is turned on or off + //Input is connected to the N64 3V3 line on the controller port. + pinMode(N64_CONSOLE_SENSE_PIN, INPUT_PULLDOWN); + pinMode(N64_FRAME_PIN, OUTPUT); + pinMode(USER_LED_PIN, OUTPUT); + +#if (ENABLE_HARDWIRED_CONTROLLER >= 1) + pinMode(HW_A, INPUT_PULLUP); + pinMode(HW_B, INPUT_PULLUP); + pinMode(HW_CU, INPUT_PULLUP); + pinMode(HW_CD, INPUT_PULLUP); + pinMode(HW_CL, INPUT_PULLUP); + pinMode(HW_CR, INPUT_PULLUP); + pinMode(HW_DU, INPUT_PULLUP); + pinMode(HW_DD, INPUT_PULLUP); + pinMode(HW_DL, INPUT_PULLUP); + pinMode(HW_DR, INPUT_PULLUP); + pinMode(HW_START, INPUT_PULLUP); + pinMode(HW_Z, INPUT_PULLUP); + pinMode(HW_R, INPUT_PULLUP); + pinMode(HW_L, INPUT_PULLUP); + pinMode(HW_EN, INPUT_PULLUP); + pinMode(HW_RUMBLE, OUTPUT); +#endif + + pinMode(N64_CONTROLLER_1_PIN, INPUT_PULLUP); + pinMode(N64_CONTROLLER_2_PIN, INPUT_PULLUP); + pinMode(N64_CONTROLLER_3_PIN, INPUT_PULLUP); + pinMode(N64_CONTROLLER_4_PIN, INPUT_PULLUP); + + NVIC_SET_PRIORITY(IRQ_GPIO6789, 1); + digitalWrite(USER_LED_PIN, HIGH); +} + void n64hal_debug_write(char c) { serial_port.write(c); @@ -111,6 +153,12 @@ uint32_t n64hal_millis() return millis(); } +dev_gpio_t *n64hal_pin_to_gpio(usb64_pin_t pin) +{ + //Not used for Arduino backend + return NULL; +} + /* * Function: Flips the gpio pin direction from an output (driven low) to an input (pulled up) * for the controller passed by controller. @@ -121,16 +169,16 @@ uint32_t n64hal_millis() * controller: Pointer to the n64 controller struct which contains the gpio mapping * val: N64_OUTPUT or N64_INPUT */ -void n64hal_input_swap(n64_input_dev_t *controller, uint8_t val) +void n64hal_input_swap(usb64_pin_t pin, uint8_t val) { switch (val) { case N64_OUTPUT: - pinMode(controller->gpio_pin, OUTPUT); + pinMode(pin, OUTPUT); break; case N64_INPUT: default: - pinMode(controller->gpio_pin, INPUT_PULLUP); + pinMode(pin, INPUT_PULLUP); break; } } @@ -143,36 +191,11 @@ void n64hal_input_swap(n64_input_dev_t *controller, uint8_t val) * * Pin number: (See usb64_conf.h) */ -uint8_t n64hal_input_read(int pin) +uint8_t n64hal_input_read(usb64_pin_t pin) { return digitalReadFast(pin); } -/* - * Function: Sets the GPIO mode of a pin - * ---------------------------- - * Returns: void - * - * Pin number (See usb64_conf.h) - * val: N64_OUTPUT or N64_INPUT_PULLDOWN or N64_INPUT_PULLUP - */ -void n64hal_pin_set_mode(int pin, uint8_t mode) -{ - switch (mode) - { - case N64_OUTPUT: - pinMode(pin, OUTPUT); - break; - case N64_INPUT_PULLDOWN: - pinMode(pin, INPUT_PULLDOWN); - break; - case N64_INPUT_PULLUP: - default: - pinMode(pin, INPUT_PULLUP); - break; - } -} - /* * Function: Sets an output GPI to a level * Speed critical! @@ -182,19 +205,25 @@ void n64hal_pin_set_mode(int pin, uint8_t mode) * pin: Arduino compatible pin number * level: 1 or 0 */ -void n64hal_output_set(uint8_t pin, uint8_t level) +void n64hal_output_set(usb64_pin_t pin, uint8_t level) { digitalWriteFast(pin, level); } -void n64hal_attach_interrupt(uint8_t pin, void (*handler)(void), int mode) +void n64hal_attach_interrupt(usb64_pin_t pin, void (*handler)(void), int mode) { int _mode = -1; switch (mode) { - case N64_INTMODE_CHANGE: _mode = CHANGE; break; - case N64_INTMODE_FALLING: _mode = FALLING; break; - case N64_INTMODE_RISING: _mode = RISING; break; + case N64_INTMODE_CHANGE: + _mode = CHANGE; + break; + case N64_INTMODE_FALLING: + _mode = FALLING; + break; + case N64_INTMODE_RISING: + _mode = RISING; + break; } if (_mode != -1) { @@ -202,7 +231,7 @@ void n64hal_attach_interrupt(uint8_t pin, void (*handler)(void), int mode) } } -void n64hal_detach_interrupt(uint8_t pin) +void n64hal_detach_interrupt(usb64_pin_t pin) { detachInterrupt(digitalPinToInterrupt(pin)); } diff --git a/src/port_teensy41/usb64_conf.h b/src/port_teensy41/usb64_conf.h index ef355682..c7cde5a6 100644 --- a/src/port_teensy41/usb64_conf.h +++ b/src/port_teensy41/usb64_conf.h @@ -43,34 +43,48 @@ #define ENABLE_HARDWIRED_CONTROLLER 1 //Ability to hardware a N64 controller into the usb64. #define PERI_CHANGE_TIME 750 //Milliseconds to simulate a peripheral changing time. Needed for some games. -/* PIN MAPPING */ -#define N64_CONSOLE_SENSE 37 -#define N64_CONTROLLER_1_PIN 36 -#define N64_CONTROLLER_2_PIN 35 -#define N64_CONTROLLER_3_PIN 34 -#define N64_CONTROLLER_4_PIN 33 -#define N64_FRAME 23 //Pulses high each time N64 console requests input. Presumably related to frames. -#define USER_LED_PIN 13 - -//Hardwired interface. All digital inputs are pulled up, active low. -#define HW_A 2 -#define HW_B 3 -#define HW_CU 4 -#define HW_CD 5 -#define HW_CL 6 -#define HW_CR 7 -#define HW_DU 8 -#define HW_DD 9 -#define HW_DL 10 -#define HW_DR 11 -#define HW_START 12 -#define HW_Z 28 -#define HW_R 29 -#define HW_L 30 -#define HW_RUMBLE 31 //Output, 1 when should be rumbling -#define HW_EN 32 //Active low, pulled high -#define HW_X 24 //Analog input, 0V to VCC. VCC/2 centre -#define HW_Y 25 //Analog input, 0V to VCC. VCC/2 centre +//Not used for Arduino backend +typedef struct +{ + int pin; +} dev_gpio_t; + +/* PIN MAPPING - Teensy uses an Arduino Backend, we just assign the enum to the Arduino Pin number + USB64_PIN_MAX must be the largest pin number in the list add one*/ +typedef enum { + N64_CONSOLE_SENSE_PIN = 37, + N64_CONTROLLER_1_PIN = 36, + N64_CONTROLLER_2_PIN = 35, + N64_CONTROLLER_3_PIN = 34, + N64_CONTROLLER_4_PIN = 33, + USER_LED_PIN = 13, + N64_FRAME_PIN = 23, + HW_A = 2, + HW_B = 3, + HW_CU = 4, + HW_CD = 5, + HW_CL = 6, + HW_CR = 7, + HW_DU = 8, + HW_DD = 9, + HW_DL = 10, + HW_DR = 11, + HW_START = 12, + HW_Z = 28, + HW_R = 29, + HW_L = 30, + HW_RUMBLE = 31, //Output, 1 when should be rumbling + HW_EN = 32, //Active low, pulled high + HW_X = 24, //Analog input, 0V to VCC. VCC/2 centre + HW_Y = 25, //Analog input, 0V to VCC. VCC/2 centre + TFT_DC = 40, + TFT_CS = 41, + TFT_MOSI = 26, + TFT_SCK = 27, + TFT_MISO = 39, + TFT_RST = -1, + USB64_PIN_MAX = 42, +} usb64_pin_t; /* FILESYSTEM */ #define MAX_FILENAME_LEN 256 @@ -92,12 +106,6 @@ /* TFT DISPLAY */ #define ENABLE_TFT_DISPLAY 1 #define TFT_ROTATION 1 //0-3 -#define TFT_DC 40 -#define TFT_CS 41 -#define TFT_MOSI 26 -#define TFT_SCK 27 -#define TFT_MISO 39 -#define TFT_RST 255 #define TFT_WIDTH 320 #define TFT_HEIGHT 240 #define TFT_PIXEL_SIZE 2 From 428021a027df9b7048d080437b1faa4cdb65a661 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 7 Dec 2021 13:51:48 +1030 Subject: [PATCH 065/121] usb64: Refactor GPIO for better portability --- src/n64_wrapper.h | 1 - src/port_null/hal_null.cpp | 10 ---------- src/port_null/usb64_conf.h | 5 ----- src/port_teensy41/hal_t4.cpp | 6 ------ src/port_teensy41/usb64_conf.h | 6 ------ 5 files changed, 28 deletions(-) diff --git a/src/n64_wrapper.h b/src/n64_wrapper.h index a462393d..c7062f11 100644 --- a/src/n64_wrapper.h +++ b/src/n64_wrapper.h @@ -45,7 +45,6 @@ void n64hal_write_extram(void *tx_buff, void *dst, uint32_t offset, uint32_t len //GPIO wrappers void n64hal_gpio_init(); -dev_gpio_t *n64hal_pin_to_gpio(usb64_pin_t pin); void n64hal_output_set(usb64_pin_t pin, uint8_t level); void n64hal_input_swap(usb64_pin_t pin, uint8_t val); uint8_t n64hal_input_read(usb64_pin_t pin); diff --git a/src/port_null/hal_null.cpp b/src/port_null/hal_null.cpp index de5750a2..bfa86ecb 100644 --- a/src/port_null/hal_null.cpp +++ b/src/port_null/hal_null.cpp @@ -169,16 +169,6 @@ uint32_t n64hal_millis() return 0; } -/* - * Function: Converts a usb64_pin_t enum (See usb64_config.h) into your device specifc gpio structure - * ---------------------------- - * Returns: Pointer to the dev_gpio_t struct defined in usb64_conf.h - */ -dev_gpio_t *n64hal_pin_to_gpio(usb64_pin_t pin) -{ - return NULL; -} - /* * Function: Flips the gpio pin direction from an output (driven low) to an input (pulled up) * for the controller passed by controller. diff --git a/src/port_null/usb64_conf.h b/src/port_null/usb64_conf.h index 71c34da7..3abff1ba 100644 --- a/src/port_null/usb64_conf.h +++ b/src/port_null/usb64_conf.h @@ -43,11 +43,6 @@ #define ENABLE_HARDWIRED_CONTROLLER 1 //Ability to hardware a N64 controller into the usb64. #define PERI_CHANGE_TIME 750 //Milliseconds to simulate a peripheral changing time. Needed for some games. -typedef struct -{ - int pin; -} dev_gpio_t; - /* PIN MAPPING */ typedef enum { USER_LED_PIN, diff --git a/src/port_teensy41/hal_t4.cpp b/src/port_teensy41/hal_t4.cpp index 50171bf2..1a0f7eaa 100644 --- a/src/port_teensy41/hal_t4.cpp +++ b/src/port_teensy41/hal_t4.cpp @@ -153,12 +153,6 @@ uint32_t n64hal_millis() return millis(); } -dev_gpio_t *n64hal_pin_to_gpio(usb64_pin_t pin) -{ - //Not used for Arduino backend - return NULL; -} - /* * Function: Flips the gpio pin direction from an output (driven low) to an input (pulled up) * for the controller passed by controller. diff --git a/src/port_teensy41/usb64_conf.h b/src/port_teensy41/usb64_conf.h index c7cde5a6..2f8f5983 100644 --- a/src/port_teensy41/usb64_conf.h +++ b/src/port_teensy41/usb64_conf.h @@ -43,12 +43,6 @@ #define ENABLE_HARDWIRED_CONTROLLER 1 //Ability to hardware a N64 controller into the usb64. #define PERI_CHANGE_TIME 750 //Milliseconds to simulate a peripheral changing time. Needed for some games. -//Not used for Arduino backend -typedef struct -{ - int pin; -} dev_gpio_t; - /* PIN MAPPING - Teensy uses an Arduino Backend, we just assign the enum to the Arduino Pin number USB64_PIN_MAX must be the largest pin number in the list add one*/ typedef enum { From 0d9641a030caab2844562354943ae2a1576ef2bb Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 11 Dec 2021 12:23:10 +1030 Subject: [PATCH 066/121] TFT: Reset update flag after draw --- src/tft.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tft.cpp b/src/tft.cpp index 0f67ddc1..280fb6bb 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -264,6 +264,8 @@ void tft_force_update() n64_status.show_window(); tft_dev_draw(true); + + _tft_update_needed = 0; } void tft_flag_update() From 2fade240800261fd30699db12e488a98713c886e Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 11 Dec 2021 12:37:09 +1030 Subject: [PATCH 067/121] TFT: Update on usb connection --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index 3969b6c6..59760b2b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -112,6 +112,7 @@ void loop() case 3: n64hal_attach_interrupt(n64_in_dev[c].pin, n64_controller4_clock_edge, N64_INTMODE_FALLING); break; } n64_in_dev[c].interrupt_attached = true; + tft_flag_update(); } if (input_is(c, INPUT_GAMECONTROLLER)) { From b24f497099d3b5a1776ca3379416a6ed72e664ac Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 14 Dec 2021 12:18:54 +1030 Subject: [PATCH 068/121] TFT: Move log generation to flush --- src/main.cpp | 2 +- src/tft.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 59760b2b..e4c7ee81 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -468,7 +468,6 @@ static char ring_buffer[4096]; extern "C" void _putchar(char character) { ring_buffer[ring_buffer_pos] = character; - tft_add_log(character); ring_buffer_pos = (ring_buffer_pos + 1) % sizeof(ring_buffer); } @@ -483,6 +482,7 @@ static void ring_buffer_flush() while (ring_buffer[_print_cursor] != 0xFF) { n64hal_debug_write(ring_buffer[_print_cursor]); + tft_add_log(ring_buffer[_print_cursor]); ring_buffer[_print_cursor] = 0xFF; _print_cursor = (_print_cursor + 1) % sizeof(ring_buffer); } diff --git a/src/tft.cpp b/src/tft.cpp index 280fb6bb..bdce1aa6 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -294,7 +294,7 @@ void tft_add_log(char c) } else { - tft_log_pos++; + tft_log_pos = (tft_log_pos + 1) % 256; } //Exceeded max lines, remove oldest line and shift lines up by one From 1fd4bed64ae25678a6be72371e81ac310ee3c764 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 14 Dec 2021 13:16:10 +1030 Subject: [PATCH 069/121] usb64: Rework includes and port configuration (again) --- platformio.ini | 11 +- src/analog_stick.cpp | 2 +- src/analog_stick.h | 2 +- src/{port_null/usb64_conf.h => common.h} | 123 +++++++++++----------- src/fileio.cpp | 2 +- src/fileio.h | 2 +- src/input.cpp | 2 +- src/input.h | 2 +- src/main.cpp | 6 +- src/memory.cpp | 5 +- src/memory.h | 2 +- src/n64/n64_controller.c | 7 -- src/n64/n64_controller.h | 4 +- src/n64/n64_mempak.c | 6 -- src/n64/n64_settings.c | 4 +- src/n64/n64_settings.h | 2 +- src/n64/n64_transferpak_gbcarts.c | 6 -- src/n64/n64_virtualpak.c | 6 -- src/n64_wrapper.h | 59 ----------- src/port_null/hal_null.cpp | 4 +- src/port_null/port_conf.h | 37 +++++++ src/port_null/tft_null.cpp | 2 +- src/port_teensy41/hal_t4.cpp | 6 +- src/port_teensy41/port_conf.h | 62 +++++++++++ src/port_teensy41/tft_t4.cpp | 2 +- src/port_teensy41/usb64_conf.h | 127 ----------------------- src/port_teensy41/usbh_t4.cpp | 2 +- src/tft.cpp | 3 +- src/tft/Arial_14.cpp | 2 +- src/tft/Arial_19.cpp | 2 +- 30 files changed, 195 insertions(+), 307 deletions(-) rename src/{port_null/usb64_conf.h => common.h} (60%) delete mode 100644 src/n64_wrapper.h create mode 100644 src/port_null/port_conf.h create mode 100644 src/port_teensy41/port_conf.h delete mode 100644 src/port_teensy41/usb64_conf.h diff --git a/platformio.ini b/platformio.ini index fbc031be..c98c825c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -43,8 +43,17 @@ build_flags = -Isrc/lib -Isrc/lib/printf -Isrc/lib/tinyusb/src + ;DEBUG OUTPUT CONFIG + -DDEBUG_STATUS=1 ;General information + -DDEBUG_N64=0 ;For debugging N64 low level info + -DDEBUG_TPAK=0 ;For debugging N64 TPAK low level info. It's complex so has its own flag + -DDEBUG_USBHOST=0 ;For debugging the USB Host Stack (1,2 or 3. Higher = more output) + -DDEBUG_MEMORY=0 ;For debugging the memory allocator in external RAM. + -DDEBUG_FATFS=0 ;For debugging the FATFS io + -DDEBUG_ERROR=1 ;For showing critical errors + -DCFG_TUSB_DEBUG_PRINTF="tusb_printf_hook" - -DCFG_TUSB_DEBUG=0 + -DCFG_TUSB_DEBUG=DEBUG_USBHOST ; Printf Configuration -DPRINTF_DISABLE_SUPPORT_FLOAT diff --git a/src/analog_stick.cpp b/src/analog_stick.cpp index 0d7e8453..e471ebf1 100644 --- a/src/analog_stick.cpp +++ b/src/analog_stick.cpp @@ -1,7 +1,7 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include "usb64_conf.h" +#include "common.h" void astick_apply_deadzone(float *out_x, float *out_y, float x, float y, float dz_low, float dz_high) { float magnitude = sqrtf(powf(x,2) + powf(y,2)); diff --git a/src/analog_stick.h b/src/analog_stick.h index 8ba00b4d..08192b1d 100644 --- a/src/analog_stick.h +++ b/src/analog_stick.h @@ -4,7 +4,7 @@ #ifndef _ANALOG_STICK_H #define _ANALOG_STICK_H -#include "usb64_conf.h" +#include "common.h" void astick_apply_deadzone(float *out_x, float *out_y, float x, float y, float dz_low, float dz_high); float astick_apply_sensitivity(int sensitivity, float *x, float *y); diff --git a/src/port_null/usb64_conf.h b/src/common.h similarity index 60% rename from src/port_null/usb64_conf.h rename to src/common.h index 3abff1ba..57ab4c36 100644 --- a/src/port_null/usb64_conf.h +++ b/src/common.h @@ -1,6 +1,9 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT +#ifndef N64_N64_WRAPPER_H_ +#define N64_N64_WRAPPER_H_ + #ifdef ARDUINO #include #endif @@ -9,30 +12,29 @@ #include #include #include - #include "printf.h" -#undef printf -#undef sprintf -#undef snprinf -#undef vsnprintf -#undef vprintf - -#ifndef _USB64_CONF_h -#define _USB64_CONF_h - -/* DEBUGGING OUTPUT - WARNING SOME OF THESE MAY BREAK TIMING AND CAUSE ISSUES - USE ONLY FOR DEBUGGING */ -#define serial_port Serial1 -#define DEBUG_STATUS 1 //General information -#define DEBUG_N64 0 //For debugging N64 low level info -#define DEBUG_TPAK 0 //For debugging N64 TPAK low level info. It's complex so has its own flag -#define DEBUG_USBHOST 0 //For debugging the USB Host Stack -#define DEBUG_FATFS 0 //For debugging the FATFS io -#define DEBUG_MEMORY 0 //For debugging the memory allocator in external RAM. -#define DEBUG_ERROR 1 //For showing critical errors - -/* USB HOST STACK */ -#define ENABLE_USB_HUB 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#define N64_OUTPUT 1 +#define N64_INPUT 2 +#define N64_INPUT_PULLUP 2 +#define N64_INPUT_PULLDOWN 3 + +#define N64_INTMODE_FALLING 1 +#define N64_INTMODE_CHANGE 2 +#define N64_INTMODE_RISING 3 + +/* DEBUG PRINTERS - See platformio.ini to enable */ +#define debug_print_status(fmt, ...) do { if (DEBUG_STATUS) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_n64(fmt, ...) do { if (DEBUG_N64) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_tpak(fmt, ...) do { if (DEBUG_TPAK) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_usbhost(fmt, ...) do { if (DEBUG_USBHOST) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_fatfs(fmt, ...) do { if (DEBUG_FATFS) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_memory(fmt, ...) do { if (DEBUG_MEMORY) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +#define debug_print_error(fmt, ...) do { if (DEBUG_ERROR) usb64_printf(fmt, ##__VA_ARGS__); } while (0) /* N64 LIB */ #define MAX_CONTROLLERS 4 //Max is 4 @@ -43,19 +45,6 @@ #define ENABLE_HARDWIRED_CONTROLLER 1 //Ability to hardware a N64 controller into the usb64. #define PERI_CHANGE_TIME 750 //Milliseconds to simulate a peripheral changing time. Needed for some games. -/* PIN MAPPING */ -typedef enum { - USER_LED_PIN, - N64_FRAME_PIN, - HW_RUMBLE, - N64_CONSOLE_SENSE_PIN, - N64_CONTROLLER_1_PIN, - N64_CONTROLLER_2_PIN, - N64_CONTROLLER_3_PIN, - N64_CONTROLLER_4_PIN, - USB64_PIN_MAX, -} usb64_pin_t; - /* FILESYSTEM */ #define MAX_FILENAME_LEN 256 #define SETTINGS_FILENAME "SETTINGS.DAT" @@ -73,30 +62,42 @@ typedef enum { #define MOUSE_SENSITIVITY 2.0f //Just what felt right to me with my mouse. #define MAG_AT_45DEG 1.1f //Octagonal shape has a larger magnitude at the 45degree points. 1.1 times larger seems about right -/* TFT DISPLAY */ -#define ENABLE_TFT_DISPLAY 1 -#define TFT_ROTATION 1 //0-3 -#define TFT_WIDTH 320 -#define TFT_HEIGHT 240 -#define TFT_PIXEL_SIZE 2 -#define TFT_USE_FRAMEBUFFER 1 - -/* Optional, to save RAM, define for variables to store in flash only */ -#ifndef PROGMEM -#define PROGMEM -#endif -/* Optional, to save RAM, define for function to store in flash only */ -#ifndef FLASHMEM -#define FLASHMEM -#endif +#include "port_conf.h" -/* DEBUG PRINTERS */ -#define debug_print_status(fmt, ...) do { if (DEBUG_STATUS) usb64_printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_n64(fmt, ...) do { if (DEBUG_N64) usb64_printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_tpak(fmt, ...) do { if (DEBUG_TPAK) usb64_printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_usbhost(fmt, ...) do { if (DEBUG_USBHOST) usb64_printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_fatfs(fmt, ...) do { if (DEBUG_FATFS) usb64_printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_memory(fmt, ...) do { if (DEBUG_MEMORY) usb64_printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_error(fmt, ...) do { if (DEBUG_ERROR) usb64_printf(fmt, ##__VA_ARGS__); } while (0) +//System wrappers +void n64hal_system_init(); +void n64hal_debug_init(); +void n64hal_debug_write(char c); +void n64hal_attach_interrupt(usb64_pin_t pin, void (*handler)(void), int mode); +void n64hal_detach_interrupt(usb64_pin_t pin); +void n64hal_disable_interrupts(); +void n64hal_enable_interrupts(); + +//RTC wrapper prototypes (For gameboy roms with RTC, i.e Pokemon games) +void n64hal_rtc_read(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s); +void n64hal_rtc_write(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s); + +//Timer wrappers +uint32_t n64hal_hs_tick_get_speed(); +void n64hal_hs_tick_init(); +uint32_t n64hal_hs_tick_get(); +uint32_t n64hal_millis(); -#endif \ No newline at end of file +//RAM access wrappers +void n64hal_read_extram(void *rx_buff, void *src, uint32_t offset, uint32_t len); +void n64hal_write_extram(void *tx_buff, void *dst, uint32_t offset, uint32_t len); + +//GPIO wrappers +void n64hal_gpio_init(); +void n64hal_output_set(usb64_pin_t pin, uint8_t level); +void n64hal_input_swap(usb64_pin_t pin, uint8_t val); +uint8_t n64hal_input_read(usb64_pin_t pin); + +//FileIO wrappers +uint32_t n64hal_list_gb_roms(char **list, uint32_t max); +void n64hal_read_storage(char *name, uint32_t file_offset, uint8_t *data, uint32_t len); + +#ifdef __cplusplus +} +#endif +#endif /* N64_N64_WRAPPER_H_ */ diff --git a/src/fileio.cpp b/src/fileio.cpp index 9976ce93..55bd0a8a 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -1,7 +1,7 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include "usb64_conf.h" +#include "common.h" #include "fileio.h" #include "memory.h" diff --git a/src/fileio.h b/src/fileio.h index 8ca54723..9be02366 100644 --- a/src/fileio.h +++ b/src/fileio.h @@ -4,7 +4,7 @@ #ifndef _FILEIO_H #define _FILEIO_H -#include "usb64_conf.h" +#include "common.h" //File access API void fileio_init(void); diff --git a/src/input.cpp b/src/input.cpp index 3382ba72..589e51be 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -1,7 +1,7 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include "usb64_conf.h" +#include "common.h" #include "n64_controller.h" #include "input.h" #include "tft.h" diff --git a/src/input.h b/src/input.h index bd7052b8..1f0b6ad8 100644 --- a/src/input.h +++ b/src/input.h @@ -4,7 +4,7 @@ #ifndef _INPUT_H #define _INPUT_H -#include "usb64_conf.h" +#include "common.h" #include "tusb.h" typedef struct diff --git a/src/main.cpp b/src/main.cpp index e4c7ee81..a5f91eff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,17 +1,13 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include "usb64_conf.h" +#include "common.h" #include "input.h" #include "n64_controller.h" -#include "n64_transferpak_gbcarts.h" -#include "n64_virtualpak.h" -#include "n64_settings.h" #include "analog_stick.h" #include "memory.h" #include "fileio.h" #include "tft.h" -#include "n64_wrapper.h" void usbh_dev_init(void); static void ring_buffer_init(void); diff --git a/src/memory.cpp b/src/memory.cpp index f627a738..a4775e5e 100644 --- a/src/memory.cpp +++ b/src/memory.cpp @@ -11,10 +11,9 @@ * and automatically flushes for you atleast. You can also manual flush with a button combo. */ -#include "usb64_conf.h" +#include "common.h" #include "memory.h" -#include "n64_wrapper.h" -#include "usb64_conf.h" +#include "common.h" #include "fileio.h" static sram_storage sram[32] = {0}; diff --git a/src/memory.h b/src/memory.h index 63071d8f..7b658977 100644 --- a/src/memory.h +++ b/src/memory.h @@ -4,7 +4,7 @@ #ifndef _MEMORY_H #define _MEMORY_H -#include "usb64_conf.h" +#include "common.h" #define MEMORY_READ_WRITE 0 #define MEMORY_READ_ONLY 1 diff --git a/src/n64/n64_controller.c b/src/n64/n64_controller.c index 1f1750ec..fe82b7de 100644 --- a/src/n64/n64_controller.c +++ b/src/n64/n64_controller.c @@ -1,14 +1,7 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include "usb64_conf.h" -#include "n64_mempak.h" -#include "n64_virtualpak.h" -#include "n64_rumblepak.h" -#include "n64_settings.h" -#include "n64_transferpak_gbcarts.h" #include "n64_controller.h" -#include "n64_wrapper.h" //Uncomment to enable mempak READ address CRC checks. //May cause timing issues. diff --git a/src/n64/n64_controller.h b/src/n64/n64_controller.h index e6118d09..5342ed8d 100644 --- a/src/n64/n64_controller.h +++ b/src/n64/n64_controller.h @@ -8,9 +8,11 @@ extern "C" { #endif -#include "usb64_conf.h" +#include #include "n64_mempak.h" #include "n64_rumblepak.h" +#include "n64_settings.h" +#include "n64_virtualpak.h" #include "n64_transferpak_gbcarts.h" typedef struct __attribute__((packed)) diff --git a/src/n64/n64_mempak.c b/src/n64/n64_mempak.c index 51213a2c..60c8af44 100644 --- a/src/n64/n64_mempak.c +++ b/src/n64/n64_mempak.c @@ -1,13 +1,7 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include "usb64_conf.h" -#include "n64_mempak.h" -#include "n64_virtualpak.h" -#include "n64_settings.h" -#include "n64_transferpak_gbcarts.h" #include "n64_controller.h" -#include "n64_wrapper.h" void n64_mempack_read32(n64_mempack *mempack, uint16_t address, uint8_t *rx_buff) { diff --git a/src/n64/n64_settings.c b/src/n64/n64_settings.c index 1fa40804..77ad5e20 100644 --- a/src/n64/n64_settings.c +++ b/src/n64/n64_settings.c @@ -1,9 +1,7 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include "usb64_conf.h" -#include "n64_settings.h" -#include "n64_wrapper.h" +#include "n64_controller.h" n64_settings *_settings = NULL; diff --git a/src/n64/n64_settings.h b/src/n64/n64_settings.h index 24c12076..63d67564 100644 --- a/src/n64/n64_settings.h +++ b/src/n64/n64_settings.h @@ -8,7 +8,7 @@ extern "C" { #endif -#include "usb64_conf.h" +#include "common.h" typedef struct { diff --git a/src/n64/n64_transferpak_gbcarts.c b/src/n64/n64_transferpak_gbcarts.c index eda6e174..89cf08e2 100644 --- a/src/n64/n64_transferpak_gbcarts.c +++ b/src/n64/n64_transferpak_gbcarts.c @@ -7,13 +7,7 @@ * Tranferpak emulation is my own RE. */ -#include "usb64_conf.h" -#include "n64_mempak.h" -#include "n64_virtualpak.h" -#include "n64_settings.h" -#include "n64_transferpak_gbcarts.h" #include "n64_controller.h" -#include "n64_wrapper.h" static uint32_t _gb_get_rom_size(uint8_t rom_type) { diff --git a/src/n64/n64_virtualpak.c b/src/n64/n64_virtualpak.c index 7143d757..40511f80 100644 --- a/src/n64/n64_virtualpak.c +++ b/src/n64/n64_virtualpak.c @@ -1,13 +1,7 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include "usb64_conf.h" -#include "n64_mempak.h" -#include "n64_virtualpak.h" -#include "n64_settings.h" -#include "n64_transferpak_gbcarts.h" #include "n64_controller.h" -#include "n64_wrapper.h" #define HEADING MENU_LINE1 #define SUBHEADING MENU_LINE2 diff --git a/src/n64_wrapper.h b/src/n64_wrapper.h deleted file mode 100644 index c7062f11..00000000 --- a/src/n64_wrapper.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#ifndef N64_N64_WRAPPER_H_ -#define N64_N64_WRAPPER_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "usb64_conf.h" -#include "n64_controller.h" - -#define N64_OUTPUT 1 -#define N64_INPUT 2 -#define N64_INPUT_PULLUP 2 -#define N64_INPUT_PULLDOWN 3 - -#define N64_INTMODE_FALLING 1 -#define N64_INTMODE_CHANGE 2 -#define N64_INTMODE_RISING 3 - -//System wrappers -void n64hal_system_init(); -void n64hal_debug_init(); -void n64hal_debug_write(char c); -void n64hal_attach_interrupt(usb64_pin_t pin, void (*handler)(void), int mode); -void n64hal_detach_interrupt(usb64_pin_t pin); -void n64hal_disable_interrupts(); -void n64hal_enable_interrupts(); - -//RTC wrapper prototypes (For gameboy roms with RTC, i.e Pokemon games) -void n64hal_rtc_read(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s); -void n64hal_rtc_write(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s); - -//Timer wrappers -uint32_t n64hal_hs_tick_get_speed(); -void n64hal_hs_tick_init(); -uint32_t n64hal_hs_tick_get(); -uint32_t n64hal_millis(); - -//RAM access wrappers -void n64hal_read_extram(void *rx_buff, void *src, uint32_t offset, uint32_t len); -void n64hal_write_extram(void *tx_buff, void *dst, uint32_t offset, uint32_t len); - -//GPIO wrappers -void n64hal_gpio_init(); -void n64hal_output_set(usb64_pin_t pin, uint8_t level); -void n64hal_input_swap(usb64_pin_t pin, uint8_t val); -uint8_t n64hal_input_read(usb64_pin_t pin); - -//FileIO wrappers -uint32_t n64hal_list_gb_roms(char **list, uint32_t max); -void n64hal_read_storage(char *name, uint32_t file_offset, uint8_t *data, uint32_t len); - -#ifdef __cplusplus -} -#endif -#endif /* N64_N64_WRAPPER_H_ */ diff --git a/src/port_null/hal_null.cpp b/src/port_null/hal_null.cpp index bfa86ecb..d80044b6 100644 --- a/src/port_null/hal_null.cpp +++ b/src/port_null/hal_null.cpp @@ -2,10 +2,8 @@ // SPDX-License-Identifier: MIT #include -#include "n64_controller.h" -#include "n64_wrapper.h" +#include "common.h" #include "memory.h" -#include "usb64_conf.h" #include "fileio.h" #include "memory.h" diff --git a/src/port_null/port_conf.h b/src/port_null/port_conf.h new file mode 100644 index 00000000..ab2d05ab --- /dev/null +++ b/src/port_null/port_conf.h @@ -0,0 +1,37 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT +#ifndef _USB64_CONF_h +#define _USB64_CONF_h + +/* PIN MAPPING - Teensy uses an Arduino Backend, we just assign the enum to the Arduino Pin number + USB64_PIN_MAX must be the largest pin number in the list add one*/ +typedef enum { + USER_LED_PIN, + N64_FRAME_PIN, + HW_RUMBLE, + N64_CONSOLE_SENSE_PIN, + N64_CONTROLLER_1_PIN, + N64_CONTROLLER_2_PIN, + N64_CONTROLLER_3_PIN, + N64_CONTROLLER_4_PIN, + USB64_PIN_MAX, +} usb64_pin_t; + +/* TFT DISPLAY */ +#define ENABLE_TFT_DISPLAY 1 +#define TFT_ROTATION 1 //0-3 +#define TFT_WIDTH 320 +#define TFT_HEIGHT 240 +#define TFT_PIXEL_SIZE 2 +#define TFT_USE_FRAMEBUFFER 1 + +/* Optional, to save RAM, define for variables to store in flash only */ +#ifndef PROGMEM +#define PROGMEM +#endif +/* Optional, to save RAM, define for function to store in flash only */ +#ifndef FLASHMEM +#define FLASHMEM +#endif + +#endif diff --git a/src/port_null/tft_null.cpp b/src/port_null/tft_null.cpp index fb7d60e0..a3b427e3 100644 --- a/src/port_null/tft_null.cpp +++ b/src/port_null/tft_null.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MIT #include -#include "usb64_conf.h" +#include "common.h" #include "controller_icon.h" #include "usb64_logo.h" #include "GuiLite.h" diff --git a/src/port_teensy41/hal_t4.cpp b/src/port_teensy41/hal_t4.cpp index 1a0f7eaa..864f5758 100644 --- a/src/port_teensy41/hal_t4.cpp +++ b/src/port_teensy41/hal_t4.cpp @@ -1,11 +1,9 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include -#include "n64_controller.h" -#include "n64_wrapper.h" +#include +#include "common.h" #include "memory.h" -#include "usb64_conf.h" #include "fileio.h" #include "memory.h" diff --git a/src/port_teensy41/port_conf.h b/src/port_teensy41/port_conf.h new file mode 100644 index 00000000..73b146fc --- /dev/null +++ b/src/port_teensy41/port_conf.h @@ -0,0 +1,62 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT +#ifndef _USB64_CONF_h +#define _USB64_CONF_h + +#define serial_port Serial1 + +/* PIN MAPPING - Teensy uses an Arduino Backend, we just assign the enum to the Arduino Pin number + USB64_PIN_MAX must be the largest pin number in the list add one*/ +typedef enum { + N64_CONSOLE_SENSE_PIN = 37, + N64_CONTROLLER_1_PIN = 36, + N64_CONTROLLER_2_PIN = 35, + N64_CONTROLLER_3_PIN = 34, + N64_CONTROLLER_4_PIN = 33, + USER_LED_PIN = 13, + N64_FRAME_PIN = 23, + HW_A = 2, + HW_B = 3, + HW_CU = 4, + HW_CD = 5, + HW_CL = 6, + HW_CR = 7, + HW_DU = 8, + HW_DD = 9, + HW_DL = 10, + HW_DR = 11, + HW_START = 12, + HW_Z = 28, + HW_R = 29, + HW_L = 30, + HW_RUMBLE = 31, //Output, 1 when should be rumbling + HW_EN = 32, //Active low, pulled high + HW_X = 24, //Analog input, 0V to VCC. VCC/2 centre + HW_Y = 25, //Analog input, 0V to VCC. VCC/2 centre + TFT_DC = 40, + TFT_CS = 41, + TFT_MOSI = 26, + TFT_SCK = 27, + TFT_MISO = 39, + TFT_RST = -1, + USB64_PIN_MAX = 42, +} usb64_pin_t; + +/* TFT DISPLAY */ +#define ENABLE_TFT_DISPLAY 1 +#define TFT_ROTATION 1 //0-3 +#define TFT_WIDTH 320 +#define TFT_HEIGHT 240 +#define TFT_PIXEL_SIZE 2 +#define TFT_USE_FRAMEBUFFER 1 + +/* Define for variables to store in flash only */ +#ifndef PROGMEM +#define PROGMEM +#endif +/* Define for function to store in flash only */ +#ifndef FLASHMEM +#define FLASHMEM +#endif + +#endif diff --git a/src/port_teensy41/tft_t4.cpp b/src/port_teensy41/tft_t4.cpp index e2559a17..4f641072 100644 --- a/src/port_teensy41/tft_t4.cpp +++ b/src/port_teensy41/tft_t4.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MIT #include -#include "usb64_conf.h" +#include "common.h" #include "controller_icon.h" #include "usb64_logo.h" #include "GuiLite.h" diff --git a/src/port_teensy41/usb64_conf.h b/src/port_teensy41/usb64_conf.h deleted file mode 100644 index 2f8f5983..00000000 --- a/src/port_teensy41/usb64_conf.h +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#ifdef ARDUINO -#include -#endif -#include -#include -#include -#include -#include - -#include "printf.h" -#undef printf -#undef sprintf -#undef snprinf -#undef vsnprintf -#undef vprintf - -#ifndef _USB64_CONF_h -#define _USB64_CONF_h - -/* DEBUGGING OUTPUT - WARNING SOME OF THESE MAY BREAK TIMING AND CAUSE ISSUES - USE ONLY FOR DEBUGGING */ -#define serial_port Serial1 -#define DEBUG_STATUS 1 //General information -#define DEBUG_N64 0 //For debugging N64 low level info -#define DEBUG_TPAK 0 //For debugging N64 TPAK low level info. It's complex so has its own flag -#define DEBUG_USBHOST 0 //For debugging the USB Host Stack -#define DEBUG_FATFS 0 //For debugging the FATFS io -#define DEBUG_MEMORY 0 //For debugging the memory allocator in external RAM. -#define DEBUG_ERROR 1 //For showing critical errors - -/* USB HOST STACK */ -#define ENABLE_USB_HUB 1 - -/* N64 LIB */ -#define MAX_CONTROLLERS 4 //Max is 4 -#define MAX_MICE 4 //0 to disable N64 mouse support. Must be <= MAX_CONTROLLERS -#define MAX_KB 4 //0 to disable N64 randnet keyboard support. Must be <= MAX_CONTROLLERS -#define MAX_GBROMS 10 //ROMS over this will just get ignored -#define ENABLE_I2C_CONTROLLERS 0 //Received button presses over I2C, useful for integrating with a rasp pi etc. -#define ENABLE_HARDWIRED_CONTROLLER 1 //Ability to hardware a N64 controller into the usb64. -#define PERI_CHANGE_TIME 750 //Milliseconds to simulate a peripheral changing time. Needed for some games. - -/* PIN MAPPING - Teensy uses an Arduino Backend, we just assign the enum to the Arduino Pin number - USB64_PIN_MAX must be the largest pin number in the list add one*/ -typedef enum { - N64_CONSOLE_SENSE_PIN = 37, - N64_CONTROLLER_1_PIN = 36, - N64_CONTROLLER_2_PIN = 35, - N64_CONTROLLER_3_PIN = 34, - N64_CONTROLLER_4_PIN = 33, - USER_LED_PIN = 13, - N64_FRAME_PIN = 23, - HW_A = 2, - HW_B = 3, - HW_CU = 4, - HW_CD = 5, - HW_CL = 6, - HW_CR = 7, - HW_DU = 8, - HW_DD = 9, - HW_DL = 10, - HW_DR = 11, - HW_START = 12, - HW_Z = 28, - HW_R = 29, - HW_L = 30, - HW_RUMBLE = 31, //Output, 1 when should be rumbling - HW_EN = 32, //Active low, pulled high - HW_X = 24, //Analog input, 0V to VCC. VCC/2 centre - HW_Y = 25, //Analog input, 0V to VCC. VCC/2 centre - TFT_DC = 40, - TFT_CS = 41, - TFT_MOSI = 26, - TFT_SCK = 27, - TFT_MISO = 39, - TFT_RST = -1, - USB64_PIN_MAX = 42, -} usb64_pin_t; - -/* FILESYSTEM */ -#define MAX_FILENAME_LEN 256 -#define SETTINGS_FILENAME "SETTINGS.DAT" -#define GAMEBOY_SAVE_EXT ".SAV" //ROMFILENAME.SAV -#define MEMPAK_SAVE_EXT ".MPK" //MEMPAKXX.MPK - -/* FIRMWARE DEFAULTS (CONFIGURABLE DURING USE) */ -#define DEFAULT_SENSITIVITY 2 //0 to 4 (0 = low sensitivity, 4 = max) -#define DEFAULT_DEADZONE 2 //0 to 4 (0 = no deadzone correction, 4 = max (40%)) -#define DEFAULT_SNAP 1 //0 or 1 (0 = will output raw analog stick angle, 1 will snap to 45deg angles) -#define DEFAULT_OCTA_CORRECT 1 //0 or 1 (Will correct the circular analog stuck shape to N64 octagonal) - -/* FIRMWARE DEFAULTS (NOT CONFIGURABLE DURING USE) */ -#define SNAP_RANGE 5 //+/- what angle range will snap. 5 will snap to 45 degree if between 40 and 50 degrees. -#define MOUSE_SENSITIVITY 2.0f //Just what felt right to me with my mouse. -#define MAG_AT_45DEG 1.1f //Octagonal shape has a larger magnitude at the 45degree points. 1.1 times larger seems about right - -/* TFT DISPLAY */ -#define ENABLE_TFT_DISPLAY 1 -#define TFT_ROTATION 1 //0-3 -#define TFT_WIDTH 320 -#define TFT_HEIGHT 240 -#define TFT_PIXEL_SIZE 2 -#define TFT_USE_FRAMEBUFFER 1 - -/* Define for variables to store in flash only */ -#ifndef PROGMEM -#define PROGMEM -#endif -/* Define for function to store in flash only */ -#ifndef FLASHMEM -#define FLASHMEM -#endif - - -/* DEBUG PRINTERS */ -#define debug_print_status(fmt, ...) do { if (DEBUG_STATUS) usb64_printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_n64(fmt, ...) do { if (DEBUG_N64) usb64_printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_tpak(fmt, ...) do { if (DEBUG_TPAK) usb64_printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_usbhost(fmt, ...) do { if (DEBUG_USBHOST) usb64_printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_fatfs(fmt, ...) do { if (DEBUG_FATFS) usb64_printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_memory(fmt, ...) do { if (DEBUG_MEMORY) usb64_printf(fmt, ##__VA_ARGS__); } while (0) -#define debug_print_error(fmt, ...) do { if (DEBUG_ERROR) usb64_printf(fmt, ##__VA_ARGS__); } while (0) - -#endif \ No newline at end of file diff --git a/src/port_teensy41/usbh_t4.cpp b/src/port_teensy41/usbh_t4.cpp index fbc868bf..b9047185 100644 --- a/src/port_teensy41/usbh_t4.cpp +++ b/src/port_teensy41/usbh_t4.cpp @@ -1,7 +1,7 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include "usb64_conf.h" +#include "common.h" #include "tusb.h" void USB_OTG2_IRQHandler(void) diff --git a/src/tft.cpp b/src/tft.cpp index bdce1aa6..c3a134c5 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -1,8 +1,7 @@ // Copyright 2020, Ryan Wendland, usb64 // SPDX-License-Identifier: MIT -#include "usb64_conf.h" -#include "n64_wrapper.h" +#include "common.h" #include "n64_controller.h" #include "input.h" #include "memory.h" diff --git a/src/tft/Arial_14.cpp b/src/tft/Arial_14.cpp index efebcae1..dac9b14d 100644 --- a/src/tft/Arial_14.cpp +++ b/src/tft/Arial_14.cpp @@ -1,4 +1,4 @@ -#include "usb64_conf.h" +#include "common.h" #include "GuiLite.h" static const unsigned char _32[] PROGMEM = { diff --git a/src/tft/Arial_19.cpp b/src/tft/Arial_19.cpp index 4b34d767..df26c029 100644 --- a/src/tft/Arial_19.cpp +++ b/src/tft/Arial_19.cpp @@ -1,4 +1,4 @@ -#include "usb64_conf.h" +#include "common.h" #include "GuiLite.h" static const unsigned char _32[] PROGMEM = { From 593ad2d23d8cf9d2fd0f0042d03a3259e7de9ce6 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 15 Dec 2021 20:43:56 +1030 Subject: [PATCH 070/121] TFT: Flag update after device disconncet --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index a5f91eff..3407074f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -188,6 +188,7 @@ void loop() { n64_in_dev[c].interrupt_attached = false; n64hal_detach_interrupt(n64_in_dev[c].pin); + tft_flag_update(); } //Get a copy of the latest n64 button presses to handle the below combos From 5a4ce0068d503c53228bbbcf978a001e6cb07f23 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 15 Dec 2021 20:48:48 +1030 Subject: [PATCH 071/121] TFT: Check malloc before use --- src/tft.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tft.cpp b/src/tft.cpp index c3a134c5..67882fce 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -285,9 +285,12 @@ void tft_add_log(char c) if (c == '\n') { tft_log[tft_log_pos] = '\0'; - _tft_log_text_lines[tft_log_line_num] = (char *)memory_dev_malloc(strlen(tft_log) + 1); - strcpy(_tft_log_text_lines[tft_log_line_num], tft_log); - tft_log_line_num++; + _tft_log_text_lines[tft_log_line_num] = (char *)malloc(strlen(tft_log) + 1); + if (_tft_log_text_lines[tft_log_line_num] != NULL) + { + strcpy(_tft_log_text_lines[tft_log_line_num], tft_log); + tft_log_line_num++; + } tft_log_pos = 0; tft_flag_update(); } From 17ca9837530aff98c1a9637c88f8b9440ab623f0 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 15 Dec 2021 20:49:38 +1030 Subject: [PATCH 072/121] N64: Make CRC function weak --- src/n64/n64_controller.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/n64/n64_controller.c b/src/n64/n64_controller.c index fe82b7de..ab1db998 100644 --- a/src/n64/n64_controller.c +++ b/src/n64/n64_controller.c @@ -49,7 +49,7 @@ void n64_subsystem_init(n64_input_dev_t *in_dev) n64hal_hs_tick_init(); } -static uint8_t n64_get_crc(uint8_t *data) +__attribute__((weak)) uint8_t n64_get_crc(uint8_t *data) { //Generated from http://www.sunshine2k.de/coding/javascript/crc/crc_js.html //N64 CRC poly was brute forced as x^7 + x^2 + x^0 (0x85), initial value = 0 From fda02697f81c21d0bf82fe22a46bcc46651d7df5 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Thu, 16 Dec 2021 17:33:05 +1030 Subject: [PATCH 073/121] TFT: Use memory malloc function --- src/tft.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tft.cpp b/src/tft.cpp index 67882fce..6e4e97ee 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -285,7 +285,7 @@ void tft_add_log(char c) if (c == '\n') { tft_log[tft_log_pos] = '\0'; - _tft_log_text_lines[tft_log_line_num] = (char *)malloc(strlen(tft_log) + 1); + _tft_log_text_lines[tft_log_line_num] = (char *)memory_dev_malloc(strlen(tft_log) + 1); if (_tft_log_text_lines[tft_log_line_num] != NULL) { strcpy(_tft_log_text_lines[tft_log_line_num], tft_log); From 414b6ee15f9c67f3e6db961b97413c20b1876aa5 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Thu, 16 Dec 2021 17:34:59 +1030 Subject: [PATCH 074/121] Null: Add malloc wrappers --- src/port_null/hal_null.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/port_null/hal_null.cpp b/src/port_null/hal_null.cpp index d80044b6..9d31fbb9 100644 --- a/src/port_null/hal_null.cpp +++ b/src/port_null/hal_null.cpp @@ -238,6 +238,28 @@ void n64hal_write_extram(void *tx_buff, void *dst, uint32_t offset, uint32_t len memory_mark_dirty(dst); } +/* + * Function: Allocates a block of memory + * ---------------------------- + * Returns: pointer to memory region + * + * len: How many bytes to allocate + */ +void *n64hal_malloc(uint32_t len) +{ + return memory_dev_malloc(len); +} + +/* + * Function: Free a block of memory + * ---------------------------- + * addr: The address to free + */ +void n64hal_free(void *addr) +{ + memory_dev_free(addr); +} + /* * Function: Returns a list of gameboy roms located on nonvolatile storage * WARNING: This mallocs memory on the heap. It must be free'd by user. From ca45e9a4c23df718b68c2e1d117f7e227848b65c Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Thu, 16 Dec 2021 17:35:18 +1030 Subject: [PATCH 075/121] T4: Add malloc wrappers --- src/port_teensy41/hal_t4.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/port_teensy41/hal_t4.cpp b/src/port_teensy41/hal_t4.cpp index 864f5758..11f1ca14 100644 --- a/src/port_teensy41/hal_t4.cpp +++ b/src/port_teensy41/hal_t4.cpp @@ -259,6 +259,28 @@ void n64hal_write_extram(void *tx_buff, void *dst, uint32_t offset, uint32_t len memory_mark_dirty(dst); } +/* + * Function: Allocates a block of memory + * ---------------------------- + * Returns: pointer to memory region + * + * len: How many bytes to allocate + */ +void *n64hal_malloc(uint32_t len) +{ + return memory_dev_malloc(len); +} + +/* + * Function: Free a block of memory + * ---------------------------- + * addr: The address to free + */ +void n64hal_free(void *addr) +{ + memory_dev_free(addr); +} + /* * Function: Returns a list of gameboy roms located on nonvolatile storage * WARNING: This mallocs memory on the heap. It must be free'd by user. From 8f047626b1d25206b42986e21ae7b3dd5ad50c98 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Thu, 16 Dec 2021 17:35:44 +1030 Subject: [PATCH 076/121] N64: Use n64 malloc wrappers --- src/n64/n64_virtualpak.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/n64/n64_virtualpak.c b/src/n64/n64_virtualpak.c index 40511f80..b45a75d0 100644 --- a/src/n64/n64_virtualpak.c +++ b/src/n64/n64_virtualpak.c @@ -205,9 +205,9 @@ void n64_virtualpak_init(n64_mempack *vpak) for (uint32_t i = 0; i < num_roms; i++) { if (gbrom_filenames[i] != NULL) - free(gbrom_filenames[i]); + n64hal_free(gbrom_filenames[i]); if (gbrom_titlenames[i] != NULL) - free(gbrom_titlenames[i]); + n64hal_free(gbrom_titlenames[i]); gbrom_filenames[i] = NULL; gbrom_titlenames[i] = NULL; @@ -225,7 +225,7 @@ void n64_virtualpak_init(n64_mempack *vpak) gb_init_cart(&gb_cart, gb_header, gbrom_filenames[i]); //Copy the gb cart title (from the rom header into an array) - gbrom_titlenames[i] = (char *)malloc(strlen(gb_cart.title) + 1); + gbrom_titlenames[i] = (char *)n64hal_malloc(strlen(gb_cart.title) + 1); strcpy(gbrom_titlenames[i], gb_cart.title); } n64_virtualpak_update(vpak); From 73635152decd771b64fa979a1696b15353ae5b75 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Thu, 16 Dec 2021 17:36:09 +1030 Subject: [PATCH 077/121] N64: Add malloc wrappers to header --- src/common.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/common.h b/src/common.h index 57ab4c36..bc422c9d 100644 --- a/src/common.h +++ b/src/common.h @@ -97,6 +97,10 @@ uint8_t n64hal_input_read(usb64_pin_t pin); uint32_t n64hal_list_gb_roms(char **list, uint32_t max); void n64hal_read_storage(char *name, uint32_t file_offset, uint8_t *data, uint32_t len); +//Memory wrappers +void *n64hal_malloc(uint32_t len); +void n64hal_free(void *addr); + #ifdef __cplusplus } #endif From 2699534928353662986b8e7bf9c669f5621398a5 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Thu, 16 Dec 2021 18:39:50 +1030 Subject: [PATCH 078/121] TinyUSBH: Update submodule --- src/lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tinyusb b/src/lib/tinyusb index 39dfa850..5565ce05 160000 --- a/src/lib/tinyusb +++ b/src/lib/tinyusb @@ -1 +1 @@ -Subproject commit 39dfa850db7a90526fa5d474a4d54d9b11695a3a +Subproject commit 5565ce0553112ae46bf49090c4c6b5908d7df361 From f1204837717432739e05b8937df597185c7e5c01 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Thu, 16 Dec 2021 18:45:14 +1030 Subject: [PATCH 079/121] usb64: Add stm32f7 port --- boards/disco_f750n8_extflash.json | 44 + .../Adafruit_Shield/Release_Notes.html | 599 ++ .../Adafruit_Shield/stm32_adafruit_lcd.c | 1067 +++ .../Adafruit_Shield/stm32_adafruit_lcd.h | 195 + .../Adafruit_Shield/stm32_adafruit_sd.c | 1048 +++ .../Adafruit_Shield/stm32_adafruit_sd.h | 247 + .../Components/Common/Release_Notes.html | 759 ++ .../bsp_drivers/Components/Common/accelero.h | 143 + .../bsp_drivers/Components/Common/audio.h | 122 + .../bsp_drivers/Components/Common/camera.h | 141 + .../bsp_drivers/Components/Common/epd.h | 115 + .../bsp_drivers/Components/Common/gyro.h | 145 + .../bsp_drivers/Components/Common/idd.h | 168 + .../common/bsp_drivers/Components/Common/io.h | 150 + .../bsp_drivers/Components/Common/lcd.h | 114 + .../bsp_drivers/Components/Common/magneto.h | 125 + .../common/bsp_drivers/Components/Common/ts.h | 107 + .../bsp_drivers/Components/Common/tsensor.h | 118 + .../Components/adv7533/Release_Notes.html | 204 + .../bsp_drivers/Components/adv7533/adv7533.c | 511 ++ .../bsp_drivers/Components/adv7533/adv7533.h | 230 + .../ampire480272/Release_Notes.html | 231 + .../Components/ampire480272/ampire480272.h | 119 + .../ampire640480/Release_Notes.html | 230 + .../Components/ampire640480/ampire640480.h | 119 + .../Components/exc7200/Release_Notes.html | 162 + .../bsp_drivers/Components/exc7200/exc7200.c | 240 + .../bsp_drivers/Components/exc7200/exc7200.h | 135 + .../Components/ft5336/Release_Notes.html | 215 + .../bsp_drivers/Components/ft5336/ft5336.c | 623 ++ .../bsp_drivers/Components/ft5336/ft5336.h | 538 ++ .../Components/ft6x06/Release_Notes.html | 202 + .../bsp_drivers/Components/ft6x06/ft6x06.c | 512 ++ .../bsp_drivers/Components/ft6x06/ft6x06.h | 469 ++ .../mfxstm32l152/Release_Notes.html | 295 + .../Components/mfxstm32l152/mfxstm32l152.c | 1602 +++++ .../Components/mfxstm32l152/mfxstm32l152.h | 666 ++ .../Components/mx25l512/Release_Notes.html | 217 + .../Components/mx25l512/mx25l512.h | 227 + .../Components/n25q128a/Release_Notes.html | 172 + .../Components/n25q128a/n25q128a.h | 217 + .../Components/n25q512a/Release_Notes.html | 180 + .../Components/n25q512a/n25q512a.h | 259 + .../Components/otm8009a/Release_Notes.html | 254 + .../Components/otm8009a/otm8009a.c | 452 ++ .../Components/otm8009a/otm8009a.h | 222 + .../Components/ov5640/Release_Notes.html | 91 + .../Components/ov5640/_htmresc/mini-st.css | 1700 +++++ .../Components/ov5640/_htmresc/st_logo.png | Bin 0 -> 18616 bytes .../bsp_drivers/Components/ov5640/ov5640.c | 1306 ++++ .../bsp_drivers/Components/ov5640/ov5640.h | 205 + .../Components/ov9655/Release_Notes.html | 230 + .../bsp_drivers/Components/ov9655/ov9655.c | 859 +++ .../bsp_drivers/Components/ov9655/ov9655.h | 157 + .../Components/rk043fn48h/Release_Notes.html | 246 + .../Components/rk043fn48h/rk043fn48h.h | 119 + .../Components/s5k5cag/Release_Notes.html | 1096 +++ .../bsp_drivers/Components/s5k5cag/s5k5cag.c | 3448 +++++++++ .../bsp_drivers/Components/s5k5cag/s5k5cag.h | 146 + .../Components/st7735/Release_Notes.html | 322 + .../bsp_drivers/Components/st7735/st7735.c | 469 ++ .../bsp_drivers/Components/st7735/st7735.h | 212 + .../Components/st7789h2/Release_Notes.html | 330 + .../Components/st7789h2/st7789h2.c | 723 ++ .../Components/st7789h2/st7789h2.h | 186 + .../Components/stmpe811/Release_Notes.html | 392 ++ .../Components/stmpe811/stmpe811.c | 975 +++ .../Components/stmpe811/stmpe811.h | 289 + .../Components/ts3510/Release_Notes.html | 294 + .../bsp_drivers/Components/ts3510/ts3510.c | 254 + .../bsp_drivers/Components/ts3510/ts3510.h | 139 + .../Components/wm8994/Release_Notes.html | 304 + .../bsp_drivers/Components/wm8994/wm8994.c | 1075 +++ .../bsp_drivers/Components/wm8994/wm8994.h | 186 + .../STM32746G-Discovery/License.md | 3 + .../STM32746G-Discovery/Release_Notes.html | 797 +++ .../STM32746G-Discovery/stm32746g_discovery.c | 902 +++ .../STM32746G-Discovery/stm32746g_discovery.h | 339 + .../stm32746g_discovery_audio.c | 1380 ++++ .../stm32746g_discovery_audio.h | 293 + .../stm32746g_discovery_camera.c | 659 ++ .../stm32746g_discovery_camera.h | 147 + .../stm32746g_discovery_eeprom.c | 477 ++ .../stm32746g_discovery_eeprom.h | 138 + .../stm32746g_discovery_lcd.c | 1663 +++++ .../stm32746g_discovery_lcd.h | 267 + .../stm32746g_discovery_qspi.c | 798 +++ .../stm32746g_discovery_qspi.h | 170 + .../stm32746g_discovery_sd.c | 606 ++ .../stm32746g_discovery_sd.h | 161 + .../stm32746g_discovery_sdram.c | 497 ++ .../stm32746g_discovery_sdram.h | 162 + .../stm32746g_discovery_ts.c | 450 ++ .../stm32746g_discovery_ts.h | 212 + .../STM32756G_EVAL/Release_Notes.html | 210 + .../STM32756G_EVAL/_htmresc/mini-st.css | 1700 +++++ .../STM32756G_EVAL/_htmresc/st_logo.png | Bin 0 -> 18616 bytes .../STM32756G_EVAL/stm32756g_eval.c | 1422 ++++ .../STM32756G_EVAL/stm32756g_eval.h | 430 ++ .../STM32756G_EVAL/stm32756g_eval_audio.c | 1396 ++++ .../STM32756G_EVAL/stm32756g_eval_audio.h | 319 + .../STM32756G_EVAL/stm32756g_eval_camera.c | 664 ++ .../STM32756G_EVAL/stm32756g_eval_camera.h | 154 + .../STM32756G_EVAL/stm32756g_eval_eeprom.c | 476 ++ .../STM32756G_EVAL/stm32756g_eval_eeprom.h | 138 + .../STM32756G_EVAL/stm32756g_eval_io.c | 325 + .../STM32756G_EVAL/stm32756g_eval_io.h | 156 + .../STM32756G_EVAL/stm32756g_eval_lcd.c | 1626 +++++ .../STM32756G_EVAL/stm32756g_eval_lcd.h | 270 + .../STM32756G_EVAL/stm32756g_eval_nor.c | 456 ++ .../STM32756G_EVAL/stm32756g_eval_nor.h | 151 + .../STM32756G_EVAL/stm32756g_eval_qspi.c | 847 +++ .../STM32756G_EVAL/stm32756g_eval_qspi.h | 170 + .../STM32756G_EVAL/stm32756g_eval_sd.c | 612 ++ .../STM32756G_EVAL/stm32756g_eval_sd.h | 163 + .../STM32756G_EVAL/stm32756g_eval_sdram.c | 504 ++ .../STM32756G_EVAL/stm32756g_eval_sdram.h | 163 + .../STM32756G_EVAL/stm32756g_eval_sram.c | 402 ++ .../STM32756G_EVAL/stm32756g_eval_sram.h | 148 + .../STM32756G_EVAL/stm32756g_eval_ts.c | 305 + .../STM32756G_EVAL/stm32756g_eval_ts.h | 140 + .../STM32F723E-Discovery/Release_Notes.html | 358 + .../stm32f723e_discovery.c | 1053 +++ .../stm32f723e_discovery.h | 411 ++ .../stm32f723e_discovery_audio.c | 1446 ++++ .../stm32f723e_discovery_audio.h | 320 + .../stm32f723e_discovery_lcd.c | 1182 ++++ .../stm32f723e_discovery_lcd.h | 233 + .../stm32f723e_discovery_psram.c | 403 ++ .../stm32f723e_discovery_psram.h | 140 + .../stm32f723e_discovery_qspi.c | 1182 ++++ .../stm32f723e_discovery_qspi.h | 175 + .../stm32f723e_discovery_ts.c | 485 ++ .../stm32f723e_discovery_ts.h | 215 + .../STM32F7308-Discovery/Release_Notes.html | 165 + .../stm32f7308_discovery.c | 1037 +++ .../stm32f7308_discovery.h | 395 ++ .../stm32f7308_discovery_audio.c | 1430 ++++ .../stm32f7308_discovery_audio.h | 304 + .../stm32f7308_discovery_lcd.c | 1166 ++++ .../stm32f7308_discovery_lcd.h | 217 + .../stm32f7308_discovery_psram.c | 387 ++ .../stm32f7308_discovery_psram.h | 124 + .../stm32f7308_discovery_qspi.c | 1166 ++++ .../stm32f7308_discovery_qspi.h | 159 + .../stm32f7308_discovery_ts.c | 469 ++ .../stm32f7308_discovery_ts.h | 199 + .../STM32F7508-Discovery/Release_Notes.html | 257 + .../stm32f7508_discovery.c | 886 +++ .../stm32f7508_discovery.h | 323 + .../stm32f7508_discovery_audio.c | 1364 ++++ .../stm32f7508_discovery_audio.h | 277 + .../stm32f7508_discovery_camera.c | 643 ++ .../stm32f7508_discovery_camera.h | 131 + .../stm32f7508_discovery_eeprom.c | 461 ++ .../stm32f7508_discovery_eeprom.h | 122 + .../stm32f7508_discovery_lcd.c | 1647 +++++ .../stm32f7508_discovery_lcd.h | 251 + .../stm32f7508_discovery_qspi.c | 782 +++ .../stm32f7508_discovery_qspi.h | 154 + .../stm32f7508_discovery_sd.c | 590 ++ .../stm32f7508_discovery_sd.h | 145 + .../stm32f7508_discovery_sdram.c | 481 ++ .../stm32f7508_discovery_sdram.h | 146 + .../stm32f7508_discovery_ts.c | 434 ++ .../stm32f7508_discovery_ts.h | 196 + .../STM32F769I-Discovery/Release_Notes.html | 524 ++ .../stm32f769i_discovery.c | 818 +++ .../stm32f769i_discovery.h | 352 + .../stm32f769i_discovery_audio.c | 2212 ++++++ .../stm32f769i_discovery_audio.h | 342 + .../stm32f769i_discovery_eeprom.c | 476 ++ .../stm32f769i_discovery_eeprom.h | 138 + .../stm32f769i_discovery_lcd.c | 1955 ++++++ .../stm32f769i_discovery_lcd.h | 414 ++ .../stm32f769i_discovery_qspi.c | 1182 ++++ .../stm32f769i_discovery_qspi.h | 175 + .../stm32f769i_discovery_sd.c | 611 ++ .../stm32f769i_discovery_sd.h | 164 + .../stm32f769i_discovery_sdram.c | 503 ++ .../stm32f769i_discovery_sdram.h | 164 + .../stm32f769i_discovery_ts.c | 484 ++ .../stm32f769i_discovery_ts.h | 211 + .../STM32F769I_EVAL/Release_Notes.html | 170 + .../STM32F769I_EVAL/_htmresc/mini-st.css | 1700 +++++ .../STM32F769I_EVAL/_htmresc/st_logo.png | Bin 0 -> 18616 bytes .../STM32F769I_EVAL/stm32f769i_eval.c | 1371 ++++ .../STM32F769I_EVAL/stm32f769i_eval.h | 436 ++ .../STM32F769I_EVAL/stm32f769i_eval_audio.c | 1642 +++++ .../STM32F769I_EVAL/stm32f769i_eval_audio.h | 323 + .../STM32F769I_EVAL/stm32f769i_eval_camera.c | 689 ++ .../STM32F769I_EVAL/stm32f769i_eval_camera.h | 166 + .../STM32F769I_EVAL/stm32f769i_eval_eeprom.c | 476 ++ .../STM32F769I_EVAL/stm32f769i_eval_eeprom.h | 138 + .../STM32F769I_EVAL/stm32f769i_eval_io.c | 335 + .../STM32F769I_EVAL/stm32f769i_eval_io.h | 157 + .../STM32F769I_EVAL/stm32f769i_eval_lcd.c | 1960 ++++++ .../STM32F769I_EVAL/stm32f769i_eval_lcd.h | 424 ++ .../STM32F769I_EVAL/stm32f769i_eval_nor.c | 461 ++ .../STM32F769I_EVAL/stm32f769i_eval_nor.h | 152 + .../STM32F769I_EVAL/stm32f769i_eval_qspi.c | 851 +++ .../STM32F769I_EVAL/stm32f769i_eval_qspi.h | 168 + .../STM32F769I_EVAL/stm32f769i_eval_sd.c | 1027 +++ .../STM32F769I_EVAL/stm32f769i_eval_sd.h | 187 + .../STM32F769I_EVAL/stm32f769i_eval_sdram.c | 503 ++ .../STM32F769I_EVAL/stm32f769i_eval_sdram.h | 163 + .../STM32F769I_EVAL/stm32f769i_eval_sram.c | 402 ++ .../STM32F769I_EVAL/stm32f769i_eval_sram.h | 148 + .../STM32F769I_EVAL/stm32f769i_eval_ts.c | 499 ++ .../STM32F769I_EVAL/stm32f769i_eval_ts.h | 210 + .../STM32F7xx_Nucleo_144/Release_Notes.html | 154 + .../stm32f7xx_nucleo_144.c | 919 +++ .../stm32f7xx_nucleo_144.h | 347 + src/port_stm32f7/common/fatfs/00history.txt | 288 + src/port_stm32f7/common/fatfs/00readme.txt | 21 + src/port_stm32f7/common/fatfs/diskio.c | 141 + src/port_stm32f7/common/fatfs/diskio.h | 80 + .../common/fatfs/drivers/sd_diskio.c | 226 + .../common/fatfs/drivers/sd_diskio.h | 31 + src/port_stm32f7/common/fatfs/ff.c | 6140 +++++++++++++++++ src/port_stm32f7/common/fatfs/ff.h | 361 + src/port_stm32f7/common/fatfs/ff_gen_drv.c | 122 + src/port_stm32f7/common/fatfs/ff_gen_drv.h | 80 + src/port_stm32f7/common/fatfs/ffconf.h | 341 + src/port_stm32f7/common/fatfs/integer.h | 38 + src/port_stm32f7/common/fatfs/option/ccsbcs.c | 388 ++ .../common/fatfs/option/syscall.c | 177 + src/port_stm32f7/common/fatfs/st_readme.txt | 221 + .../common/stm32f7xx_hal_timebase_tim.c | 181 + src/port_stm32f7/common/stm32f7xx_it.c | 83 + src/port_stm32f7/common/stm32fxx_hcd.c | 330 + src/port_stm32f7/common/system_stm32f7xx.c | 422 ++ .../stm37f750-dk/STM32F750N8HX_EXTFLASH.ld | 177 + .../stm37f750-dk/fileio_stm32.cpp | 138 + src/port_stm32f7/stm37f750-dk/hal_stm32.cpp | 509 ++ src/port_stm32f7/stm37f750-dk/main.h | 377 + .../stm37f750-dk/memory_stm32.cpp | 75 + src/port_stm32f7/stm37f750-dk/port_conf.h | 71 + src/port_stm32f7/stm37f750-dk/tft_stm32.cpp | 88 + src/port_stm32f7/stm37f750-dk/usbh_stm32.cpp | 44 + 240 files changed, 116295 insertions(+) create mode 100644 boards/disco_f750n8_extflash.json create mode 100644 src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_lcd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_lcd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_sd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_sd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/Common/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/Common/accelero.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/Common/audio.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/Common/camera.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/Common/epd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/Common/gyro.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/Common/idd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/Common/io.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/Common/lcd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/Common/magneto.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/Common/ts.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/Common/tsensor.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/adv7533/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/adv7533/adv7533.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/adv7533/adv7533.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ampire480272/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ampire480272/ampire480272.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ampire640480/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ampire640480/ampire640480.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/exc7200/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/exc7200/exc7200.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/exc7200/exc7200.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ft5336/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ft5336/ft5336.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ft5336/ft5336.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ft6x06/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ft6x06/ft6x06.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ft6x06/ft6x06.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/mfxstm32l152/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/mfxstm32l152/mfxstm32l152.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/mfxstm32l152/mfxstm32l152.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/mx25l512/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/mx25l512/mx25l512.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/n25q128a/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/n25q128a/n25q128a.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/n25q512a/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/n25q512a/n25q512a.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/otm8009a/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/otm8009a/otm8009a.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/otm8009a/otm8009a.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ov5640/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ov5640/_htmresc/mini-st.css create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ov5640/_htmresc/st_logo.png create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ov5640/ov5640.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ov5640/ov5640.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ov9655/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ov9655/ov9655.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ov9655/ov9655.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/rk043fn48h/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/rk043fn48h/rk043fn48h.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/s5k5cag/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/s5k5cag/s5k5cag.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/s5k5cag/s5k5cag.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/st7735/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/st7735/st7735.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/st7735/st7735.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/st7789h2/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/st7789h2/st7789h2.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/st7789h2/st7789h2.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/stmpe811/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/stmpe811/stmpe811.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/stmpe811/stmpe811.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ts3510/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ts3510/ts3510.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/ts3510/ts3510.h create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/wm8994/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/wm8994/wm8994.c create mode 100644 src/port_stm32f7/common/bsp_drivers/Components/wm8994/wm8994.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/License.md create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_audio.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_audio.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_camera.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_camera.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_eeprom.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_eeprom.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_lcd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_lcd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_qspi.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_qspi.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sdram.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sdram.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_ts.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_ts.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/_htmresc/mini-st.css create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/_htmresc/st_logo.png create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_audio.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_audio.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_camera.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_camera.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_eeprom.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_eeprom.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_io.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_io.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_lcd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_lcd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_nor.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_nor.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_qspi.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_qspi.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sdram.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sdram.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sram.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sram.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_ts.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_ts.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_audio.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_audio.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_lcd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_lcd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_psram.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_psram.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_qspi.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_qspi.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_ts.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_ts.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_audio.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_audio.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_lcd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_lcd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_psram.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_psram.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_qspi.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_qspi.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_ts.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_ts.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_audio.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_audio.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_camera.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_camera.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_eeprom.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_eeprom.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_lcd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_lcd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_qspi.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_qspi.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sdram.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sdram.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_ts.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_ts.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_audio.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_audio.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_eeprom.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_eeprom.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_lcd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_lcd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_qspi.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_qspi.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sdram.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sdram.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_ts.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_ts.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/_htmresc/mini-st.css create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/_htmresc/st_logo.png create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_audio.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_audio.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_camera.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_camera.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_eeprom.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_eeprom.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_io.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_io.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_lcd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_lcd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_nor.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_nor.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_qspi.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_qspi.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sd.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sd.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sdram.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sdram.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sram.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sram.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_ts.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_ts.h create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7xx_Nucleo_144/Release_Notes.html create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7xx_Nucleo_144/stm32f7xx_nucleo_144.c create mode 100644 src/port_stm32f7/common/bsp_drivers/STM32F7xx_Nucleo_144/stm32f7xx_nucleo_144.h create mode 100644 src/port_stm32f7/common/fatfs/00history.txt create mode 100644 src/port_stm32f7/common/fatfs/00readme.txt create mode 100644 src/port_stm32f7/common/fatfs/diskio.c create mode 100644 src/port_stm32f7/common/fatfs/diskio.h create mode 100644 src/port_stm32f7/common/fatfs/drivers/sd_diskio.c create mode 100644 src/port_stm32f7/common/fatfs/drivers/sd_diskio.h create mode 100644 src/port_stm32f7/common/fatfs/ff.c create mode 100644 src/port_stm32f7/common/fatfs/ff.h create mode 100644 src/port_stm32f7/common/fatfs/ff_gen_drv.c create mode 100644 src/port_stm32f7/common/fatfs/ff_gen_drv.h create mode 100644 src/port_stm32f7/common/fatfs/ffconf.h create mode 100644 src/port_stm32f7/common/fatfs/integer.h create mode 100644 src/port_stm32f7/common/fatfs/option/ccsbcs.c create mode 100644 src/port_stm32f7/common/fatfs/option/syscall.c create mode 100644 src/port_stm32f7/common/fatfs/st_readme.txt create mode 100644 src/port_stm32f7/common/stm32f7xx_hal_timebase_tim.c create mode 100644 src/port_stm32f7/common/stm32f7xx_it.c create mode 100644 src/port_stm32f7/common/stm32fxx_hcd.c create mode 100644 src/port_stm32f7/common/system_stm32f7xx.c create mode 100644 src/port_stm32f7/stm37f750-dk/STM32F750N8HX_EXTFLASH.ld create mode 100644 src/port_stm32f7/stm37f750-dk/fileio_stm32.cpp create mode 100644 src/port_stm32f7/stm37f750-dk/hal_stm32.cpp create mode 100644 src/port_stm32f7/stm37f750-dk/main.h create mode 100644 src/port_stm32f7/stm37f750-dk/memory_stm32.cpp create mode 100644 src/port_stm32f7/stm37f750-dk/port_conf.h create mode 100644 src/port_stm32f7/stm37f750-dk/tft_stm32.cpp create mode 100644 src/port_stm32f7/stm37f750-dk/usbh_stm32.cpp diff --git a/boards/disco_f750n8_extflash.json b/boards/disco_f750n8_extflash.json new file mode 100644 index 00000000..a1902d56 --- /dev/null +++ b/boards/disco_f750n8_extflash.json @@ -0,0 +1,44 @@ +{ + "build": { + "cpu": "cortex-m7", + "extra_flags": "-DSTM32F750xx", + "f_cpu": "216000000L", + "mcu": "stm32f750n8h6", + "product_line": "STM32F750xx" + }, + "connectivity": [ + "can", + "ethernet" + ], + "debug": { + "default_tools": [ + "stlink" + ], + "jlink_device": "STM32F750N8", + "onboard_tools": [ + "stlink" + ], + "openocd_board": "stm32f7discovery", + "openocd_target": "stm32f7x", + "svd_path": "STM32F750x.svd" + }, + "frameworks": [ + "cmsis", + "stm32cube", + "libopencm3" + ], + "name": "STM32F7508-DK", + "upload": { + "maximum_ram_size": 327680, + "maximum_size": 16777216, + "protocol": "stlink", + "protocols": [ + "jlink", + "cmsis-dap", + "stlink", + "blackmagic" + ] + }, + "url": "https://www.st.com/content/st_com/en/products/evaluation-tools/product-evaluation-tools/mcu-mpu-eval-tools/stm32-mcu-mpu-eval-tools/stm32-discovery-kits/stm32f7508-dk.html", + "vendor": "ST" +} diff --git a/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/Release_Notes.html new file mode 100644 index 00000000..1b181fcd --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/Release_Notes.html @@ -0,0 +1,599 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Release Notes for Adafruit_Shield Drivers + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for Adafruit_Shield  Drivers

+

Copyright +2016 STMicroelectronics

+

+
+

 

+ + + + + + +

The BSP (Board Specific +Package) drivers are parts of the STM32Cube package based on the HAL +drivers and provide a set of high level APIs relative to the hardware +components and features in the evaluation boards, discovery kits and nucleo +boards coming with the STM32Cube package for a given STM32 serie.

+

The BSP drivers allow a quick access to the boards’ +services using high level APIs and without any specific configuration as the +link with the HAL and the external components is done in intrinsic within the drivers.
+

+

From project settings points of view, user has only +to add the necessary driver’s files in the workspace and call the needed +functions from examples. However some low level +configuration functions are weak and can be overridden by the applications if user +wants to change some BSP drivers default behavior.

+ + +

    Update History

V3.0.3 / 30-April-2018

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • stm32_adafruit_sd.c:
    • Fix BSP_SD_ReadBlocks and BSP_SD_WriteBlocks to support SDHC cards

V3.0.2 / 24-August-2017

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • stm32_adafruit_lcd.c:
    • Fix compilation errors with SW4STM32 toolchain

V3.0.1 / 02-June-2017

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • Add general description of BSP drivers
    +
  • Add Dependencies section
    +
  • Support of PDSC

V3.0.0 / 23-December-2016

+ + +

Main Changes

+ + +
    +
  • Update BSP_SD_ReadBlocks and BSP_SD_WriteBlocks following new HAL SD drivers implementation
  • +
  • Update BSP_SD_Erase implementation to manage SDHC and SDSC cards
  • +
  • Fix block size to 512 bytes for all card types
    + Notes: 
  • +
      +
    • These Adafruit BSP drivers break the compatibility with previous versions.
    • +
    • If FatFs is required, "FatFS R0.11 ST modified 20161223" must be used with this version of Adafruit BSP drivers.
    • +
    + +
+

V2.0.1 / 04-November-2015

+

Main Changes

+
    +
  • Fix GNU GCC warning on missing break instruction in SD_GetDataResponse()
  • +
+

V2.0.0 / 10-September-2015

+ +

Main Changes

+
    +
  • Improve SD over SPI protocol implementation
  • Note: This new implementation requires to increase Heap_Size by 0x200 
  • Note: This driver version needs BSP Nucleo driver V2.0.0 and later
  • +
+

V1.1.1 / 21-November-2014

+ + + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • stm32_adafruit_sd.c
    +
  • +
      +
    • Add workaround for the issue seen on some STM32 Nucleo boards; reading the SD card status will return an error
    • +
    • A fix will be implemented in next release
      +
    • +
    +
  • stm32_adafruit_lcd.h: change "\" by "/" in the include path to fix compilation issue under Linux
    +
  • +
  • Miscellaneous comments update
  • +
+ +

V1.1.0 / 22-July-2014

+

Main +Changes

+ + + +
    +
  • Add new user API BSP_LCD_DrawBitmap() to draw a bitmap picture loaded in the STM32 MCU internal memory
  • +
  • Add new static API SetDisplayWindow(), needed by BSP_LCD_DrawBitmap()
    +
  • +
  • Update static API DrawChar()
  • +
  • Note: This driver version needs ST7735 component driver V1.1.0 and later.
    +
  • + +
+

V1.0.0 / 22-April-2014

Main +Changes

+ +
  • First official release.

License

+
+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+
+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_lcd.c b/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_lcd.c new file mode 100644 index 00000000..cc00060f --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_lcd.c @@ -0,0 +1,1067 @@ +/** + ****************************************************************************** + * @file stm32_adafruit_lcd.c + * @author MCD Application Team + * @brief This file includes the driver for Liquid Crystal Display (LCD) module + * mounted on the Adafruit 1.8" TFT LCD shield (reference ID 802), + * that is used with the STM32 Nucleo board through SPI interface. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* File Info : ----------------------------------------------------------------- + User NOTES +1. How To use this driver: +-------------------------- + - The LCD st7735 component driver MUST be included with this driver. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the LCD using the BSP_LCD_Init() function. + + + Display on LCD + o Clear the whole LCD using the BSP_LCD_Clear() function or only one specified + string line using the BSP_LCD_ClearStringLine() function. + o Display a character on the specified line and column using the BSP_LCD_DisplayChar() + function or a complete string line using the BSP_LCD_DisplayStringAtLine() function. + o Display a string line on the specified position (x,y in pixel) and align mode + using the BSP_LCD_DisplayStringAtLine() function. + o Draw and fill a basic shapes (dot, line, rectangle, circle, ellipse, ..) + on LCD using a set of functions. + +------------------------------------------------------------------------------*/ + +/* Dependencies +- st7735.c +- fonts.h +- font24.c +- font20.c +- font16.c +- font12.c +- font8.c" +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32_adafruit_lcd.h" +#include "../../../Utilities/Fonts/fonts.h" +#include "../../../Utilities/Fonts/font24.c" +#include "../../../Utilities/Fonts/font20.c" +#include "../../../Utilities/Fonts/font16.c" +#include "../../../Utilities/Fonts/font12.c" +#include "../../../Utilities/Fonts/font8.c" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32_ADAFRUIT + * @{ + */ + +/** @addtogroup STM32_ADAFRUIT_LCD + * @{ + */ + +/** @defgroup STM32_ADAFRUIT_LCD_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @defgroup STM32_ADAFRUIT_LCD_Private_Defines + * @{ + */ +#define POLY_X(Z) ((int32_t)((Points + (Z))->X)) +#define POLY_Y(Z) ((int32_t)((Points + (Z))->Y)) +#define NULL (void *)0 + +#define MAX_HEIGHT_FONT 17 +#define MAX_WIDTH_FONT 24 +#define OFFSET_BITMAP 54 +/** + * @} + */ + +/** @defgroup STM32_ADAFRUIT_LCD_Private_Macros + * @{ + */ +#define ABS(X) ((X) > 0 ? (X) : -(X)) + +/** + * @} + */ + +/** @defgroup STM32_ADAFRUIT_LCD_Private_Variables + * @{ + */ +LCD_DrawPropTypeDef DrawProp; + +static LCD_DrvTypeDef *lcd_drv; + +/* Max size of bitmap will based on a font24 (17x24) */ +static uint8_t bitmap[MAX_HEIGHT_FONT*MAX_WIDTH_FONT*2+OFFSET_BITMAP] = {0}; + +/** + * @} + */ + +/** @defgroup STM32_ADAFRUIT_LCD_Private_FunctionPrototypes + * @{ + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c); +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3); +static void SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +/** + * @} + */ + + +/** @defgroup STM32_ADAFRUIT_LCD_Private_Functions + * @{ + */ + +/** + * @brief Initializes the LCD. + * @param None + * @retval LCD state + */ +uint8_t BSP_LCD_Init(void) +{ + uint8_t ret = LCD_ERROR; + + /* Default value for draw propriety */ + DrawProp.BackColor = 0xFFFF; + DrawProp.pFont = &Font24; + DrawProp.TextColor = 0x0000; + + lcd_drv = &st7735_drv; + + /* LCD Init */ + lcd_drv->Init(); + + /* Clear the LCD screen */ + BSP_LCD_Clear(LCD_COLOR_WHITE); + + /* Initialize the font */ + BSP_LCD_SetFont(&LCD_DEFAULT_FONT); + + ret = LCD_OK; + + return ret; +} + +/** + * @brief Gets the LCD X size. + * @param None + * @retval Used LCD X size + */ +uint32_t BSP_LCD_GetXSize(void) +{ + return(lcd_drv->GetLcdPixelWidth()); +} + +/** + * @brief Gets the LCD Y size. + * @param None + * @retval Used LCD Y size + */ +uint32_t BSP_LCD_GetYSize(void) +{ + return(lcd_drv->GetLcdPixelHeight()); +} + +/** + * @brief Gets the LCD text color. + * @param None + * @retval Used text color. + */ +uint16_t BSP_LCD_GetTextColor(void) +{ + return DrawProp.TextColor; +} + +/** + * @brief Gets the LCD background color. + * @param None + * @retval Used background color + */ +uint16_t BSP_LCD_GetBackColor(void) +{ + return DrawProp.BackColor; +} + +/** + * @brief Sets the LCD text color. + * @param Color: Text color code RGB(5-6-5) + * @retval None + */ +void BSP_LCD_SetTextColor(uint16_t Color) +{ + DrawProp.TextColor = Color; +} + +/** + * @brief Sets the LCD background color. + * @param Color: Background color code RGB(5-6-5) + * @retval None + */ +void BSP_LCD_SetBackColor(uint16_t Color) +{ + DrawProp.BackColor = Color; +} + +/** + * @brief Sets the LCD text font. + * @param fonts: Font to be used + * @retval None + */ +void BSP_LCD_SetFont(sFONT *pFonts) +{ + DrawProp.pFont = pFonts; +} + +/** + * @brief Gets the LCD text font. + * @param None + * @retval Used font + */ +sFONT *BSP_LCD_GetFont(void) +{ + return DrawProp.pFont; +} + +/** + * @brief Clears the hole LCD. + * @param Color: Color of the background + * @retval None + */ +void BSP_LCD_Clear(uint16_t Color) +{ + uint32_t counter = 0; + uint32_t color_backup = DrawProp.TextColor; + DrawProp.TextColor = Color; + + for(counter = 0; counter < BSP_LCD_GetYSize(); counter++) + { + BSP_LCD_DrawHLine(0, counter, BSP_LCD_GetXSize()); + } + DrawProp.TextColor = color_backup; + BSP_LCD_SetTextColor(DrawProp.TextColor); +} + +/** + * @brief Clears the selected line. + * @param Line: Line to be cleared + * This parameter can be one of the following values: + * @arg 0..9: if the Current fonts is Font16x24 + * @arg 0..19: if the Current fonts is Font12x12 or Font8x12 + * @arg 0..29: if the Current fonts is Font8x8 + * @retval None + */ +void BSP_LCD_ClearStringLine(uint16_t Line) +{ + uint32_t color_backup = DrawProp.TextColor; + DrawProp.TextColor = DrawProp.BackColor;; + + /* Draw a rectangle with background color */ + BSP_LCD_FillRect(0, (Line * DrawProp.pFont->Height), BSP_LCD_GetXSize(), DrawProp.pFont->Height); + + DrawProp.TextColor = color_backup; + BSP_LCD_SetTextColor(DrawProp.TextColor); +} + +/** + * @brief Displays one character. + * @param Xpos: Start column address + * @param Ypos: Line where to display the character shape. + * @param Ascii: Character ascii code + * This parameter must be a number between Min_Data = 0x20 and Max_Data = 0x7E + * @retval None + */ +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii) +{ + DrawChar(Xpos, Ypos, &DrawProp.pFont->table[(Ascii-' ') *\ + DrawProp.pFont->Height * ((DrawProp.pFont->Width + 7) / 8)]); +} + +/** + * @brief Displays characters on the LCD. + * @param Xpos: X position (in pixel) + * @param Ypos: Y position (in pixel) + * @param Text: Pointer to string to display on LCD + * @param Mode: Display mode + * This parameter can be one of the following values: + * @arg CENTER_MODE + * @arg RIGHT_MODE + * @arg LEFT_MODE + * @retval None + */ +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Line_ModeTypdef Mode) +{ + uint16_t refcolumn = 1, i = 0; + uint32_t size = 0, xsize = 0; + uint8_t *ptr = Text; + + /* Get the text size */ + while (*ptr++) size ++ ; + + /* Characters number per line */ + xsize = (BSP_LCD_GetXSize()/DrawProp.pFont->Width); + + switch (Mode) + { + case CENTER_MODE: + { + refcolumn = Xpos + ((xsize - size)* DrawProp.pFont->Width) / 2; + break; + } + case LEFT_MODE: + { + refcolumn = Xpos; + break; + } + case RIGHT_MODE: + { + refcolumn = - Xpos + ((xsize - size)*DrawProp.pFont->Width); + break; + } + default: + { + refcolumn = Xpos; + break; + } + } + + /* Send the string character by character on lCD */ + while ((*Text != 0) & (((BSP_LCD_GetXSize() - (i*DrawProp.pFont->Width)) & 0xFFFF) >= DrawProp.pFont->Width)) + { + /* Display one character on LCD */ + BSP_LCD_DisplayChar(refcolumn, Ypos, *Text); + /* Decrement the column position by 16 */ + refcolumn += DrawProp.pFont->Width; + /* Point on the next character */ + Text++; + i++; + } +} + +/** + * @brief Displays a character on the LCD. + * @param Line: Line where to display the character shape + * This parameter can be one of the following values: + * @arg 0..19: if the Current fonts is Font8 + * @arg 0..12: if the Current fonts is Font12 + * @arg 0...9: if the Current fonts is Font16 + * @arg 0...7: if the Current fonts is Font20 + * @arg 0...5: if the Current fonts is Font24 + * @param ptr: Pointer to string to display on LCD + * @retval None + */ +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr) +{ + BSP_LCD_DisplayStringAt(0, LINE(Line), ptr, LEFT_MODE); +} + +/** + * @brief Draws a pixel on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param RGB_Code: Pixel color in RGB mode (5-6-5) + * @retval None + */ +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGB_Code) +{ + if(lcd_drv->WritePixel != NULL) + { + lcd_drv->WritePixel(Xpos, Ypos, RGB_Code); + } +} + +/** + * @brief Draws an horizontal line. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + * @retval None + */ +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t index = 0; + + if(lcd_drv->DrawHLine != NULL) + { + lcd_drv->DrawHLine(DrawProp.TextColor, Xpos, Ypos, Length); + } + else + { + for(index = 0; index < Length; index++) + { + BSP_LCD_DrawPixel((Xpos + index), Ypos, DrawProp.TextColor); + } + } +} + +/** + * @brief Draws a vertical line. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + * @retval None + */ +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t index = 0; + + if(lcd_drv->DrawVLine != NULL) + { + lcd_drv->DrawVLine(DrawProp.TextColor, Xpos, Ypos, Length); + } + else + { + for(index = 0; index < Length; index++) + { + BSP_LCD_DrawPixel(Xpos, Ypos + index, DrawProp.TextColor); + } + } +} + +/** + * @brief Draws an uni-line (between two points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @retval None + */ +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + numadd = deltay; + numpixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + numadd = deltax; + numpixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= numpixels; curpixel++) + { + BSP_LCD_DrawPixel(x, y, DrawProp.TextColor); /* Draw the current pixel */ + num += numadd; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Draws a rectangle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + * @retval None + */ +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Draw horizontal lines */ + BSP_LCD_DrawHLine(Xpos, Ypos, Width); + BSP_LCD_DrawHLine(Xpos, (Ypos+ Height), Width); + + /* Draw vertical lines */ + BSP_LCD_DrawVLine(Xpos, Ypos, Height); + BSP_LCD_DrawVLine((Xpos + Width), Ypos, Height); +} + +/** + * @brief Draws a circle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + * @retval None + */ +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t D; /* Decision Variable */ + uint32_t CurX; /* Current X Value */ + uint32_t CurY; /* Current Y Value */ + + D = 3 - (Radius << 1); + CurX = 0; + CurY = Radius; + + while (CurX <= CurY) + { + BSP_LCD_DrawPixel((Xpos + CurX), (Ypos - CurY), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos - CurX), (Ypos - CurY), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos + CurY), (Ypos - CurX), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos - CurY), (Ypos - CurX), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos + CurX), (Ypos + CurY), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos - CurX), (Ypos + CurY), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos + CurY), (Ypos + CurX), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos - CurY), (Ypos + CurX), DrawProp.TextColor); + + /* Initialize the font */ + BSP_LCD_SetFont(&LCD_DEFAULT_FONT); + + if (D < 0) + { + D += (CurX << 2) + 6; + } + else + { + D += ((CurX - CurY) << 2) + 10; + CurY--; + } + CurX++; + } +} + +/** + * @brief Draws an poly-line (between many points). + * @param Points: Pointer to the points array + * @param PointCount: Number of points + * @retval None + */ +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t X = 0, Y = 0; + + if(PointCount < 2) + { + return; + } + + BSP_LCD_DrawLine(Points->X, Points->Y, (Points+PointCount-1)->X, (Points+PointCount-1)->Y); + + while(--PointCount) + { + X = Points->X; + Y = Points->Y; + Points++; + BSP_LCD_DrawLine(X, Y, Points->X, Points->Y); + } +} + +/** + * @brief Draws an ellipse on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + * @retval None + */ +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float K = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + K = (float)(rad2/rad1); + + do { + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/K)), (Ypos+y), DrawProp.TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/K)), (Ypos+y), DrawProp.TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/K)), (Ypos-y), DrawProp.TextColor); + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/K)), (Ypos-y), DrawProp.TextColor); + + e2 = err; + if (e2 <= x) { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Draws a bitmap picture loaded in the STM32 MCU internal memory. + * @param Xpos: Bmp X position in the LCD + * @param Ypos: Bmp Y position in the LCD + * @param pBmp: Pointer to Bmp picture address + * @retval None + */ +void BSP_LCD_DrawBitmap(uint16_t Xpos, uint16_t Ypos, uint8_t *pBmp) +{ + uint32_t height = 0; + uint32_t width = 0; + + /* Read bitmap width */ + width = pBmp[18] + (pBmp[19] << 8) + (pBmp[20] << 16) + (pBmp[21] << 24); + + /* Read bitmap height */ + height = pBmp[22] + (pBmp[23] << 8) + (pBmp[24] << 16) + (pBmp[25] << 24); + + /* Remap Ypos, st7735 works with inverted X in case of bitmap */ + /* X = 0, cursor is on Top corner */ + if(lcd_drv == &st7735_drv) + { + Ypos = BSP_LCD_GetYSize() - Ypos - height; + } + + SetDisplayWindow(Xpos, Ypos, width, height); + + if(lcd_drv->DrawBitmap != NULL) + { + lcd_drv->DrawBitmap(Xpos, Ypos, pBmp); + } + SetDisplayWindow(0, 0, BSP_LCD_GetXSize(), BSP_LCD_GetYSize()); +} + +/** + * @brief Draws a full rectangle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + * @retval None + */ +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + BSP_LCD_SetTextColor(DrawProp.TextColor); + do + { + BSP_LCD_DrawHLine(Xpos, Ypos++, Width); + } + while(Height--); +} + +/** + * @brief Draws a full circle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + * @retval None + */ +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t D; /* Decision Variable */ + uint32_t CurX; /* Current X Value */ + uint32_t CurY; /* Current Y Value */ + + D = 3 - (Radius << 1); + + CurX = 0; + CurY = Radius; + + BSP_LCD_SetTextColor(DrawProp.TextColor); + + while (CurX <= CurY) + { + if(CurY > 0) + { + BSP_LCD_DrawHLine(Xpos - CurY, Ypos + CurX, 2*CurY); + BSP_LCD_DrawHLine(Xpos - CurY, Ypos - CurX, 2*CurY); + } + + if(CurX > 0) + { + BSP_LCD_DrawHLine(Xpos - CurX, Ypos - CurY, 2*CurX); + BSP_LCD_DrawHLine(Xpos - CurX, Ypos + CurY, 2*CurX); + } + if (D < 0) + { + D += (CurX << 2) + 6; + } + else + { + D += ((CurX - CurY) << 2) + 10; + CurY--; + } + CurX++; + } + + BSP_LCD_SetTextColor(DrawProp.TextColor); + BSP_LCD_DrawCircle(Xpos, Ypos, Radius); +} + +/** + * @brief Draws a full poly-line (between many points). + * @param Points: Pointer to the points array + * @param PointCount: Number of points + * @retval None + */ +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t X = 0, Y = 0, X2 = 0, Y2 = 0, X_center = 0, Y_center = 0, X_first = 0, Y_first = 0, pixelX = 0, pixelY = 0, counter = 0; + uint16_t IMAGE_LEFT = 0, IMAGE_RIGHT = 0, IMAGE_TOP = 0, IMAGE_BOTTOM = 0; + + IMAGE_LEFT = IMAGE_RIGHT = Points->X; + IMAGE_TOP= IMAGE_BOTTOM = Points->Y; + + for(counter = 1; counter < PointCount; counter++) + { + pixelX = POLY_X(counter); + if(pixelX < IMAGE_LEFT) + { + IMAGE_LEFT = pixelX; + } + if(pixelX > IMAGE_RIGHT) + { + IMAGE_RIGHT = pixelX; + } + + pixelY = POLY_Y(counter); + if(pixelY < IMAGE_TOP) + { + IMAGE_TOP = pixelY; + } + if(pixelY > IMAGE_BOTTOM) + { + IMAGE_BOTTOM = pixelY; + } + } + + if(PointCount < 2) + { + return; + } + + X_center = (IMAGE_LEFT + IMAGE_RIGHT)/2; + Y_center = (IMAGE_BOTTOM + IMAGE_TOP)/2; + + X_first = Points->X; + Y_first = Points->Y; + + while(--PointCount) + { + X = Points->X; + Y = Points->Y; + Points++; + X2 = Points->X; + Y2 = Points->Y; + + FillTriangle(X, X2, X_center, Y, Y2, Y_center); + FillTriangle(X, X_center, X2, Y, Y_center, Y2); + FillTriangle(X_center, X2, X, Y_center, Y2, Y); + } + + FillTriangle(X_first, X2, X_center, Y_first, Y2, Y_center); + FillTriangle(X_first, X_center, X2, Y_first, Y_center, Y2); + FillTriangle(X_center, X2, X_first, Y_center, Y2, Y_first); +} + +/** + * @brief Draws a full ellipse. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + * @retval None + */ +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float K = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + K = (float)(rad2/rad1); + + do + { + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/K)), (Ypos+y), (2*(uint16_t)(x/K) + 1)); + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/K)), (Ypos-y), (2*(uint16_t)(x/K) + 1)); + + e2 = err; + if (e2 <= x) + { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Enables the display. + * @param None + * @retval None + */ +void BSP_LCD_DisplayOn(void) +{ + lcd_drv->DisplayOn(); +} + +/** + * @brief Disables the display. + * @param None + * @retval None + */ +void BSP_LCD_DisplayOff(void) +{ + lcd_drv->DisplayOff(); +} + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Draws a character on LCD. + * @param Xpos: Line where to display the character shape + * @param Ypos: Start column address + * @param pChar: Pointer to the character data + * @retval None + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *pChar) +{ + uint32_t counterh = 0, counterw = 0, index = 0; + uint16_t height = 0, width = 0; + uint8_t offset = 0; + uint8_t *pchar = NULL; + uint32_t line = 0; + + height = DrawProp.pFont->Height; + width = DrawProp.pFont->Width; + + /* Fill bitmap header*/ + *(uint16_t *) (bitmap + 2) = (uint16_t)(height*width*2+OFFSET_BITMAP); + *(uint16_t *) (bitmap + 4) = (uint16_t)((height*width*2+OFFSET_BITMAP)>>16); + *(uint16_t *) (bitmap + 10) = OFFSET_BITMAP; + *(uint16_t *) (bitmap + 18) = (uint16_t)(width); + *(uint16_t *) (bitmap + 20) = (uint16_t)((width)>>16); + *(uint16_t *) (bitmap + 22) = (uint16_t)(height); + *(uint16_t *) (bitmap + 24) = (uint16_t)((height)>>16); + + offset = 8 *((width + 7)/8) - width ; + + for(counterh = 0; counterh < height; counterh++) + { + pchar = ((uint8_t *)pChar + (width + 7)/8 * counterh); + + if(((width + 7)/8) == 3) + { + line = (pchar[0]<< 16) | (pchar[1]<< 8) | pchar[2]; + } + + if(((width + 7)/8) == 2) + { + line = (pchar[0]<< 8) | pchar[1]; + } + + if(((width + 7)/8) == 1) + { + line = pchar[0]; + } + + for (counterw = 0; counterw < width; counterw++) + { + /* Image in the bitmap is written from the bottom to the top */ + /* Need to invert image in the bitmap */ + index = (((height-counterh-1)*width)+(counterw))*2+OFFSET_BITMAP; + if(line & (1 << (width- counterw + offset- 1))) + { + bitmap[index] = (uint8_t)DrawProp.TextColor; + bitmap[index+1] = (uint8_t)(DrawProp.TextColor >> 8); + } + else + { + bitmap[index] = (uint8_t)DrawProp.BackColor; + bitmap[index+1] = (uint8_t)(DrawProp.BackColor >> 8); + } + } + } + + BSP_LCD_DrawBitmap(Xpos, Ypos, bitmap); +} + +/** + * @brief Fills a triangle (between 3 points). + * @param Points: Pointer to the points array + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @param x3: Point 3 X position + * @param y3: Point 3 Y position + * @retval None + */ +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + numadd = deltay; + numpixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + numadd = deltax; + numpixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= numpixels; curpixel++) + { + BSP_LCD_DrawLine(x, y, x3, y3); + + num += numadd; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Sets display window. + * @param LayerIndex: layer index + * @param Xpos: LCD X position + * @param Ypos: LCD Y position + * @param Width: LCD window width + * @param Height: LCD window height + * @retval None + */ +static void SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + if(lcd_drv->SetDisplayWindow != NULL) + { + lcd_drv->SetDisplayWindow(Xpos, Ypos, Width, Height); + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_lcd.h b/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_lcd.h new file mode 100644 index 00000000..0799e592 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_lcd.h @@ -0,0 +1,195 @@ +/** + ****************************************************************************** + * @file stm32_adafruit_lcd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32_adafruit_lcd.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32_ADAFRUIT_LCD_H +#define __STM32_ADAFRUIT_LCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "../Components/st7735/st7735.h" +#include "../../../Utilities/Fonts/fonts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32_ADAFRUIT + * @{ + */ + +/** @addtogroup STM32_ADAFRUIT_LCD + * @{ + */ + + +/** @defgroup STM32_ADAFRUIT_LCD_Exported_Types + * @{ + */ + +/** + * @brief Draw Properties structures definition + */ +typedef struct +{ + uint32_t TextColor; + uint32_t BackColor; + sFONT *pFont; + +}LCD_DrawPropTypeDef; + +/** + * @brief Point structures definition + */ +typedef struct +{ + int16_t X; + int16_t Y; + +}Point, * pPoint; + +/** + * @brief Line mode structures definition + */ +typedef enum +{ + CENTER_MODE = 0x01, /*!< Center mode */ + RIGHT_MODE = 0x02, /*!< Right mode */ + LEFT_MODE = 0x03 /*!< Left mode */ + +}Line_ModeTypdef; + +/** + * @} + */ + +/** @defgroup STM32_ADAFRUIT_LCD_Exported_Constants + * @{ + */ + +#define __IO volatile + +/** + * @brief LCD status structure definition + */ +#define LCD_OK 0x00 +#define LCD_ERROR 0x01 +#define LCD_TIMEOUT 0x02 + +/** + * @brief LCD color + */ +#define LCD_COLOR_BLACK 0x0000 +#define LCD_COLOR_GREY 0xF7DE +#define LCD_COLOR_BLUE 0x001F +#define LCD_COLOR_RED 0xF800 +#define LCD_COLOR_GREEN 0x07E0 +#define LCD_COLOR_CYAN 0x07FF +#define LCD_COLOR_MAGENTA 0xF81F +#define LCD_COLOR_YELLOW 0xFFE0 +#define LCD_COLOR_WHITE 0xFFFF + +/** + * @brief LCD default font + */ +#define LCD_DEFAULT_FONT Font8 + +/** + * @} + */ + +/** @defgroup STM32_ADAFRUIT_LCD_Exported_Functions + * @{ + */ +uint8_t BSP_LCD_Init(void); +uint32_t BSP_LCD_GetXSize(void); +uint32_t BSP_LCD_GetYSize(void); + +uint16_t BSP_LCD_GetTextColor(void); +uint16_t BSP_LCD_GetBackColor(void); +void BSP_LCD_SetTextColor(__IO uint16_t Color); +void BSP_LCD_SetBackColor(__IO uint16_t Color); +void BSP_LCD_SetFont(sFONT *fonts); +sFONT *BSP_LCD_GetFont(void); + +void BSP_LCD_Clear(uint16_t Color); +void BSP_LCD_ClearStringLine(uint16_t Line); +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr); +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Line_ModeTypdef Mode); +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii); + +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGB_Code); +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius); +void BSP_LCD_DrawBitmap(uint16_t Xpos, uint16_t Ypos, uint8_t *pBmp); +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius); + +void BSP_LCD_DisplayOff(void); +void BSP_LCD_DisplayOn(void); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32_ADAFRUIT_LCD_H */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_sd.c b/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_sd.c new file mode 100644 index 00000000..beae8b25 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_sd.c @@ -0,0 +1,1048 @@ +/** + ****************************************************************************** + * @file stm32_adafruit_sd.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the SD card + * mounted on the Adafruit 1.8" TFT LCD shield (reference ID 802), + * that is used with the STM32 Nucleo board through SPI interface. + * It implements a high level communication layer for read and write + * from/to this memory. The needed STM32XXxx hardware resources (SPI and + * GPIO) are defined in stm32XXxx_nucleo.h file, and the initialization is + * performed in SD_IO_Init() function declared in stm32XXxx_nucleo.c + * file. + * You can easily tailor this driver to any other development board, + * by just adapting the defines for hardware resources and + * SD_IO_Init() function. + * + * +-------------------------------------------------------+ + * | Pin assignment | + * +-------------------------+---------------+-------------+ + * | STM32XXxx SPI Pins | SD | Pin | + * +-------------------------+---------------+-------------+ + * | SD_SPI_CS_PIN | ChipSelect | 1 | + * | SD_SPI_MOSI_PIN / MOSI | DataIn | 2 | + * | | GND | 3 (0 V) | + * | | VDD | 4 (3.3 V)| + * | SD_SPI_SCK_PIN / SCLK | Clock | 5 | + * | | GND | 6 (0 V) | + * | SD_SPI_MISO_PIN / MISO | DataOut | 7 | + * +-------------------------+---------------+-------------+ + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* File Info : ----------------------------------------------------------------- + User NOTES +1. How to use this driver: +-------------------------- + - This driver does not need a specific component driver for the micro SD device + to be included with. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the micro SD card using the BSP_SD_Init() function. + o Checking the SD card presence is not managed because SD detection pin is + not physically mapped on the Adafruit shield. + o The function BSP_SD_GetCardInfo() is used to get the micro SD card information + which is stored in the structure "SD_CardInfo". + + + Micro SD card operations + o The micro SD card can be accessed with read/write block(s) operations once + it is ready for access. The access can be performed in polling + mode by calling the functions BSP_SD_ReadBlocks()/BSP_SD_WriteBlocks() + + o The SD erase block(s) is performed using the function BSP_SD_Erase() with + specifying the number of blocks to erase. + o The SD runtime status is returned when calling the function BSP_SD_GetStatus(). + +------------------------------------------------------------------------------*/ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32_adafruit_sd.h" +#include "stdlib.h" +#include "string.h" +#include "stdio.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32_ADAFRUIT + * @{ + */ + +/** @defgroup STM32_ADAFRUIT_SD + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ + +/** @defgroup STM32_ADAFRUIT_SD_Private_Types_Definitions + * @{ + */ +typedef struct { + uint8_t r1; + uint8_t r2; + uint8_t r3; + uint8_t r4; + uint8_t r5; +} SD_CmdAnswer_typedef; + +/** + * @} + */ + +/* Private define ------------------------------------------------------------*/ + +/** @defgroup STM32_ADAFRUIT_SD_Private_Defines + * @{ + */ +#define SD_DUMMY_BYTE 0xFF + +#define SD_MAX_FRAME_LENGTH 17 /* Lenght = 16 + 1 */ +#define SD_CMD_LENGTH 6 + +#define SD_MAX_TRY 100 /* Number of try */ + +#define SD_CSD_STRUCT_V1 0x2 /* CSD struct version V1 */ +#define SD_CSD_STRUCT_V2 0x1 /* CSD struct version V2 */ + + +/** + * @brief SD ansewer format + */ +typedef enum { + SD_ANSWER_R1_EXPECTED, + SD_ANSWER_R1B_EXPECTED, + SD_ANSWER_R2_EXPECTED, + SD_ANSWER_R3_EXPECTED, + SD_ANSWER_R4R5_EXPECTED, + SD_ANSWER_R7_EXPECTED, +}SD_Answer_type; + +/** + * @brief Start Data tokens: + * Tokens (necessary because at nop/idle (and CS active) only 0xff is + * on the data/command line) + */ +#define SD_TOKEN_START_DATA_SINGLE_BLOCK_READ 0xFE /* Data token start byte, Start Single Block Read */ +#define SD_TOKEN_START_DATA_MULTIPLE_BLOCK_READ 0xFE /* Data token start byte, Start Multiple Block Read */ +#define SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE 0xFE /* Data token start byte, Start Single Block Write */ +#define SD_TOKEN_START_DATA_MULTIPLE_BLOCK_WRITE 0xFD /* Data token start byte, Start Multiple Block Write */ +#define SD_TOKEN_STOP_DATA_MULTIPLE_BLOCK_WRITE 0xFD /* Data toke stop byte, Stop Multiple Block Write */ + +/** + * @brief Commands: CMDxx = CMD-number | 0x40 + */ +#define SD_CMD_GO_IDLE_STATE 0 /* CMD0 = 0x40 */ +#define SD_CMD_SEND_OP_COND 1 /* CMD1 = 0x41 */ +#define SD_CMD_SEND_IF_COND 8 /* CMD8 = 0x48 */ +#define SD_CMD_SEND_CSD 9 /* CMD9 = 0x49 */ +#define SD_CMD_SEND_CID 10 /* CMD10 = 0x4A */ +#define SD_CMD_STOP_TRANSMISSION 12 /* CMD12 = 0x4C */ +#define SD_CMD_SEND_STATUS 13 /* CMD13 = 0x4D */ +#define SD_CMD_SET_BLOCKLEN 16 /* CMD16 = 0x50 */ +#define SD_CMD_READ_SINGLE_BLOCK 17 /* CMD17 = 0x51 */ +#define SD_CMD_READ_MULT_BLOCK 18 /* CMD18 = 0x52 */ +#define SD_CMD_SET_BLOCK_COUNT 23 /* CMD23 = 0x57 */ +#define SD_CMD_WRITE_SINGLE_BLOCK 24 /* CMD24 = 0x58 */ +#define SD_CMD_WRITE_MULT_BLOCK 25 /* CMD25 = 0x59 */ +#define SD_CMD_PROG_CSD 27 /* CMD27 = 0x5B */ +#define SD_CMD_SET_WRITE_PROT 28 /* CMD28 = 0x5C */ +#define SD_CMD_CLR_WRITE_PROT 29 /* CMD29 = 0x5D */ +#define SD_CMD_SEND_WRITE_PROT 30 /* CMD30 = 0x5E */ +#define SD_CMD_SD_ERASE_GRP_START 32 /* CMD32 = 0x60 */ +#define SD_CMD_SD_ERASE_GRP_END 33 /* CMD33 = 0x61 */ +#define SD_CMD_UNTAG_SECTOR 34 /* CMD34 = 0x62 */ +#define SD_CMD_ERASE_GRP_START 35 /* CMD35 = 0x63 */ +#define SD_CMD_ERASE_GRP_END 36 /* CMD36 = 0x64 */ +#define SD_CMD_UNTAG_ERASE_GROUP 37 /* CMD37 = 0x65 */ +#define SD_CMD_ERASE 38 /* CMD38 = 0x66 */ +#define SD_CMD_SD_APP_OP_COND 41 /* CMD41 = 0x69 */ +#define SD_CMD_APP_CMD 55 /* CMD55 = 0x77 */ +#define SD_CMD_READ_OCR 58 /* CMD55 = 0x79 */ + +/** + * @brief SD reponses and error flags + */ +typedef enum +{ +/* R1 answer value */ + SD_R1_NO_ERROR = (0x00), + SD_R1_IN_IDLE_STATE = (0x01), + SD_R1_ERASE_RESET = (0x02), + SD_R1_ILLEGAL_COMMAND = (0x04), + SD_R1_COM_CRC_ERROR = (0x08), + SD_R1_ERASE_SEQUENCE_ERROR= (0x10), + SD_R1_ADDRESS_ERROR = (0x20), + SD_R1_PARAMETER_ERROR = (0x40), + +/* R2 answer value */ + SD_R2_NO_ERROR = 0x00, + SD_R2_CARD_LOCKED = 0x01, + SD_R2_LOCKUNLOCK_ERROR = 0x02, + SD_R2_ERROR = 0x04, + SD_R2_CC_ERROR = 0x08, + SD_R2_CARD_ECC_FAILED = 0x10, + SD_R2_WP_VIOLATION = 0x20, + SD_R2_ERASE_PARAM = 0x40, + SD_R2_OUTOFRANGE = 0x80, + +/** + * @brief Data response error + */ + SD_DATA_OK = (0x05), + SD_DATA_CRC_ERROR = (0x0B), + SD_DATA_WRITE_ERROR = (0x0D), + SD_DATA_OTHER_ERROR = (0xFF) +} SD_Error; + +/** + * @} + */ + +/* Private macro -------------------------------------------------------------*/ + +/** @defgroup STM32_ADAFRUIT_SD_Private_Macros + * @{ + */ + +/** + * @} + */ + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup STM32_ADAFRUIT_SD_Private_Variables + * @{ + */ +__IO uint8_t SdStatus = SD_NOT_PRESENT; + +/* flag_SDHC : + 0 : Standard capacity + 1 : High capacity +*/ +uint16_t flag_SDHC = 0; + +/** + * @} + */ + +/* Private function prototypes -----------------------------------------------*/ +static uint8_t SD_GetCIDRegister(SD_CID* Cid); +static uint8_t SD_GetCSDRegister(SD_CSD* Csd); +static uint8_t SD_GetDataResponse(void); +static uint8_t SD_GoIdleState(void); +static SD_CmdAnswer_typedef SD_SendCmd(uint8_t Cmd, uint32_t Arg, uint8_t Crc, uint8_t Answer); +static uint8_t SD_WaitData(uint8_t data); +static uint8_t SD_ReadData(void); +/** @defgroup STM32_ADAFRUIT_SD_Private_Function_Prototypes + * @{ + */ +/** + * @} + */ + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup STM32_ADAFRUIT_SD_Private_Functions + * @{ + */ + +/** + * @brief Initializes the SD/SD communication. + * @param None + * @retval The SD Response: + * - MSD_ERROR: Sequence failed + * - MSD_OK: Sequence succeed + */ +uint8_t BSP_SD_Init(void) +{ + /* Configure IO functionalities for SD pin */ + SD_IO_Init(); + + /* SD detection pin is not physically mapped on the Adafruit shield */ + SdStatus = SD_PRESENT; + + /* SD initialized and set to SPI mode properly */ + return SD_GoIdleState(); +} + +/** + * @brief Returns information about specific card. + * @param pCardInfo: Pointer to a SD_CardInfo structure that contains all SD + * card information. + * @retval The SD Response: + * - MSD_ERROR: Sequence failed + * - MSD_OK: Sequence succeed + */ +uint8_t BSP_SD_GetCardInfo(SD_CardInfo *pCardInfo) +{ + uint8_t status; + + status = SD_GetCSDRegister(&(pCardInfo->Csd)); + status|= SD_GetCIDRegister(&(pCardInfo->Cid)); + if(flag_SDHC == 1 ) + { + pCardInfo->LogBlockSize = 512; + pCardInfo->CardBlockSize = 512; + pCardInfo->CardCapacity = (pCardInfo->Csd.version.v2.DeviceSize + 1) * 1024 * pCardInfo->LogBlockSize; + pCardInfo->LogBlockNbr = (pCardInfo->CardCapacity) / (pCardInfo->LogBlockSize); + } + else + { + pCardInfo->CardCapacity = (pCardInfo->Csd.version.v1.DeviceSize + 1) ; + pCardInfo->CardCapacity *= (1 << (pCardInfo->Csd.version.v1.DeviceSizeMul + 2)); + pCardInfo->LogBlockSize = 512; + pCardInfo->CardBlockSize = 1 << (pCardInfo->Csd.RdBlockLen); + pCardInfo->CardCapacity *= pCardInfo->CardBlockSize; + pCardInfo->LogBlockNbr = (pCardInfo->CardCapacity) / (pCardInfo->LogBlockSize); + } + + return status; +} + +/** + * @brief Reads block(s) from a specified address in the SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read. The address is counted + * in blocks of 512bytes + * @param NumOfBlocks: Number of SD blocks to read + * @param Timeout: This parameter is used for compatibility with BSP implementation + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + uint32_t offset = 0; + uint32_t addr; + uint8_t retr = BSP_SD_ERROR; + uint8_t *ptr = NULL; + SD_CmdAnswer_typedef response; + uint16_t BlockSize = 512; + + /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and + Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_SET_BLOCKLEN, BlockSize, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if ( response.r1 != SD_R1_NO_ERROR) + { + goto error; + } + + ptr = malloc(sizeof(uint8_t)*BlockSize); + if( ptr == NULL ) + { + goto error; + } + memset(ptr, SD_DUMMY_BYTE, sizeof(uint8_t)*BlockSize); + + /* Initialize the address */ + addr = (ReadAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); + + /* Data transfer */ + while (NumOfBlocks--) + { + /* Send CMD17 (SD_CMD_READ_SINGLE_BLOCK) to read one block */ + /* Check if the SD acknowledged the read block command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_READ_SINGLE_BLOCK, addr, 0xFF, SD_ANSWER_R1_EXPECTED); + if ( response.r1 != SD_R1_NO_ERROR) + { + goto error; + } + + /* Now look for the data token to signify the start of the data */ + if (SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) + { + /* Read the SD block data : read NumByteToRead data */ + SD_IO_WriteReadData(ptr, (uint8_t*)pData + offset, BlockSize); + + /* Set next read address*/ + offset += BlockSize; + addr = ((flag_SDHC == 1) ? (addr + 1) : (addr + BlockSize)); + + /* get CRC bytes (not really needed by us, but required by SD) */ + SD_IO_WriteByte(SD_DUMMY_BYTE); + SD_IO_WriteByte(SD_DUMMY_BYTE); + } + else + { + goto error; + } + + /* End the command data read cycle */ + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + } + + retr = BSP_SD_OK; + +error : + /* Send dummy byte: 8 Clock pulses of delay */ + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(ptr != NULL) free(ptr); + + /* Return the reponse */ + return retr; +} + +/** + * @brief Writes block(s) to a specified address in the SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written. The address is counted + * in blocks of 512bytes + * @param NumOfBlocks: Number of SD blocks to write + * @param Timeout: This parameter is used for compatibility with BSP implementation + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + uint32_t offset = 0; + uint32_t addr; + uint8_t retr = BSP_SD_ERROR; + uint8_t *ptr = NULL; + SD_CmdAnswer_typedef response; + uint16_t BlockSize = 512; + + /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and + Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_SET_BLOCKLEN, BlockSize, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if ( response.r1 != SD_R1_NO_ERROR) + { + goto error; + } + + ptr = malloc(sizeof(uint8_t)*BlockSize); + if (ptr == NULL) + { + goto error; + } + + /* Initialize the address */ + addr = (WriteAddr * ((flag_SDHC == 1) ? 1 : BlockSize)); + + /* Data transfer */ + while (NumOfBlocks--) + { + /* Send CMD24 (SD_CMD_WRITE_SINGLE_BLOCK) to write blocks and + Check if the SD acknowledged the write block command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_WRITE_SINGLE_BLOCK, addr, 0xFF, SD_ANSWER_R1_EXPECTED); + if (response.r1 != SD_R1_NO_ERROR) + { + goto error; + } + + /* Send dummy byte for NWR timing : one byte between CMDWRITE and TOKEN */ + SD_IO_WriteByte(SD_DUMMY_BYTE); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Send the data token to signify the start of the data */ + SD_IO_WriteByte(SD_TOKEN_START_DATA_SINGLE_BLOCK_WRITE); + + /* Write the block data to SD */ + SD_IO_WriteReadData((uint8_t*)pData + offset, ptr, BlockSize); + + /* Set next write address */ + offset += BlockSize; + addr = ((flag_SDHC == 1) ? (addr + 1) : (addr + BlockSize)); + + /* Put CRC bytes (not really needed by us, but required by SD) */ + SD_IO_WriteByte(SD_DUMMY_BYTE); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Read data response */ + if (SD_GetDataResponse() != SD_DATA_OK) + { + /* Set response value to failure */ + goto error; + } + + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + } + retr = BSP_SD_OK; + +error : + if(ptr != NULL) free(ptr); + /* Send dummy byte: 8 Clock pulses of delay */ + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Return the reponse */ + return retr; +} + +/** + * @brief Erases the specified memory area of the given SD card. + * @param StartAddr: Start address in Blocks (Size of a block is 512bytes) + * @param EndAddr: End address in Blocks (Size of a block is 512bytes) + * @retval SD status + */ +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr) +{ + uint8_t retr = BSP_SD_ERROR; + SD_CmdAnswer_typedef response; + uint16_t BlockSize = 512; + + /* Send CMD32 (Erase group start) and check if the SD acknowledged the erase command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_SD_ERASE_GRP_START, (StartAddr) * (flag_SDHC == 1 ? 1 : BlockSize), 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); if (response.r1 == SD_R1_NO_ERROR) + { + /* Send CMD33 (Erase group end) and Check if the SD acknowledged the erase command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_SD_ERASE_GRP_END, (EndAddr*512) * (flag_SDHC == 1 ? 1 : BlockSize), 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if (response.r1 == SD_R1_NO_ERROR) + { + /* Send CMD38 (Erase) and Check if the SD acknowledged the erase command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_ERASE, 0, 0xFF, SD_ANSWER_R1B_EXPECTED); + if (response.r1 == SD_R1_NO_ERROR) + { + retr = BSP_SD_OK; + } + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + } + } + + /* Return the reponse */ + return retr; +} + +/** + * @brief Returns the SD status. + * @param None + * @retval The SD status. + */ +uint8_t BSP_SD_GetCardState(void) +{ + SD_CmdAnswer_typedef retr; + + /* Send CMD13 (SD_SEND_STATUS) to get SD status */ + retr = SD_SendCmd(SD_CMD_SEND_STATUS, 0, 0xFF, SD_ANSWER_R2_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Find SD status according to card state */ + if(( retr.r1 == SD_R1_NO_ERROR) && ( retr.r2 == SD_R2_NO_ERROR)) + { + return BSP_SD_OK; + } + + return BSP_SD_ERROR; +} + +/** + * @brief Reads the SD card SCD register. + * Reading the contents of the CSD register in SPI mode is a simple + * read-block transaction. + * @param Csd: pointer on an SCD register structure + * @retval SD status + */ +uint8_t SD_GetCSDRegister(SD_CSD* Csd) +{ + uint16_t counter = 0; + uint8_t CSD_Tab[16]; + uint8_t retr = BSP_SD_ERROR; + SD_CmdAnswer_typedef response; + + /* Send CMD9 (CSD register) or CMD10(CSD register) and Wait for response in the R1 format (0x00 is no errors) */ + response = SD_SendCmd(SD_CMD_SEND_CSD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); + if(response.r1 == SD_R1_NO_ERROR) + { + if (SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) + { + for (counter = 0; counter < 16; counter++) + { + /* Store CSD register value on CSD_Tab */ + CSD_Tab[counter] = SD_IO_WriteByte(SD_DUMMY_BYTE); + } + + /* Get CRC bytes (not really needed by us, but required by SD) */ + SD_IO_WriteByte(SD_DUMMY_BYTE); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /************************************************************************* + CSD header decoding + *************************************************************************/ + + /* Byte 0 */ + Csd->CSDStruct = (CSD_Tab[0] & 0xC0) >> 6; + Csd->Reserved1 = CSD_Tab[0] & 0x3F; + + /* Byte 1 */ + Csd->TAAC = CSD_Tab[1]; + + /* Byte 2 */ + Csd->NSAC = CSD_Tab[2]; + + /* Byte 3 */ + Csd->MaxBusClkFrec = CSD_Tab[3]; + + /* Byte 4/5 */ + Csd->CardComdClasses = (CSD_Tab[4] << 4) | ((CSD_Tab[5] & 0xF0) >> 4); + Csd->RdBlockLen = CSD_Tab[5] & 0x0F; + + /* Byte 6 */ + Csd->PartBlockRead = (CSD_Tab[6] & 0x80) >> 7; + Csd->WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6; + Csd->RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5; + Csd->DSRImpl = (CSD_Tab[6] & 0x10) >> 4; + + /************************************************************************* + CSD v1/v2 decoding + *************************************************************************/ + + if(flag_SDHC == 0) + { + Csd->version.v1.Reserved1 = ((CSD_Tab[6] & 0x0C) >> 2); + + Csd->version.v1.DeviceSize = ((CSD_Tab[6] & 0x03) << 10) + | (CSD_Tab[7] << 2) + | ((CSD_Tab[8] & 0xC0) >> 6); + Csd->version.v1.MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3; + Csd->version.v1.MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07); + Csd->version.v1.MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5; + Csd->version.v1.MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2; + Csd->version.v1.DeviceSizeMul = ((CSD_Tab[9] & 0x03) << 1) + |((CSD_Tab[10] & 0x80) >> 7); + } + else + { + Csd->version.v2.Reserved1 = ((CSD_Tab[6] & 0x0F) << 2) | ((CSD_Tab[7] & 0xC0) >> 6); + Csd->version.v2.DeviceSize= ((CSD_Tab[7] & 0x3F) << 16) | (CSD_Tab[8] << 8) | CSD_Tab[9]; + Csd->version.v2.Reserved2 = ((CSD_Tab[10] & 0x80) >> 8); + } + + Csd->EraseSingleBlockEnable = (CSD_Tab[10] & 0x40) >> 6; + Csd->EraseSectorSize = ((CSD_Tab[10] & 0x3F) << 1) + |((CSD_Tab[11] & 0x80) >> 7); + Csd->WrProtectGrSize = (CSD_Tab[11] & 0x7F); + Csd->WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7; + Csd->Reserved2 = (CSD_Tab[12] & 0x60) >> 5; + Csd->WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2; + Csd->MaxWrBlockLen = ((CSD_Tab[12] & 0x03) << 2) + |((CSD_Tab[13] & 0xC0) >> 6); + Csd->WriteBlockPartial = (CSD_Tab[13] & 0x20) >> 5; + Csd->Reserved3 = (CSD_Tab[13] & 0x1F); + Csd->FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7; + Csd->CopyFlag = (CSD_Tab[14] & 0x40) >> 6; + Csd->PermWrProtect = (CSD_Tab[14] & 0x20) >> 5; + Csd->TempWrProtect = (CSD_Tab[14] & 0x10) >> 4; + Csd->FileFormat = (CSD_Tab[14] & 0x0C) >> 2; + Csd->Reserved4 = (CSD_Tab[14] & 0x03); + Csd->crc = (CSD_Tab[15] & 0xFE) >> 1; + Csd->Reserved5 = (CSD_Tab[15] & 0x01); + + retr = BSP_SD_OK; + } + } + + /* Send dummy byte: 8 Clock pulses of delay */ + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Return the reponse */ + return retr; +} + +/** + * @brief Reads the SD card CID register. + * Reading the contents of the CID register in SPI mode is a simple + * read-block transaction. + * @param Cid: pointer on an CID register structure + * @retval SD status + */ +uint8_t SD_GetCIDRegister(SD_CID* Cid) +{ + uint32_t counter = 0; + uint8_t retr = BSP_SD_ERROR; + uint8_t CID_Tab[16]; + SD_CmdAnswer_typedef response; + + /* Send CMD10 (CID register) and Wait for response in the R1 format (0x00 is no errors) */ + response = SD_SendCmd(SD_CMD_SEND_CID, 0, 0xFF, SD_ANSWER_R1_EXPECTED); + if(response.r1 == SD_R1_NO_ERROR) + { + if(SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK) + { + /* Store CID register value on CID_Tab */ + for (counter = 0; counter < 16; counter++) + { + CID_Tab[counter] = SD_IO_WriteByte(SD_DUMMY_BYTE); + } + + /* Get CRC bytes (not really needed by us, but required by SD) */ + SD_IO_WriteByte(SD_DUMMY_BYTE); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Byte 0 */ + Cid->ManufacturerID = CID_Tab[0]; + + /* Byte 1 */ + Cid->OEM_AppliID = CID_Tab[1] << 8; + + /* Byte 2 */ + Cid->OEM_AppliID |= CID_Tab[2]; + + /* Byte 3 */ + Cid->ProdName1 = CID_Tab[3] << 24; + + /* Byte 4 */ + Cid->ProdName1 |= CID_Tab[4] << 16; + + /* Byte 5 */ + Cid->ProdName1 |= CID_Tab[5] << 8; + + /* Byte 6 */ + Cid->ProdName1 |= CID_Tab[6]; + + /* Byte 7 */ + Cid->ProdName2 = CID_Tab[7]; + + /* Byte 8 */ + Cid->ProdRev = CID_Tab[8]; + + /* Byte 9 */ + Cid->ProdSN = CID_Tab[9] << 24; + + /* Byte 10 */ + Cid->ProdSN |= CID_Tab[10] << 16; + + /* Byte 11 */ + Cid->ProdSN |= CID_Tab[11] << 8; + + /* Byte 12 */ + Cid->ProdSN |= CID_Tab[12]; + + /* Byte 13 */ + Cid->Reserved1 |= (CID_Tab[13] & 0xF0) >> 4; + Cid->ManufactDate = (CID_Tab[13] & 0x0F) << 8; + + /* Byte 14 */ + Cid->ManufactDate |= CID_Tab[14]; + + /* Byte 15 */ + Cid->CID_CRC = (CID_Tab[15] & 0xFE) >> 1; + Cid->Reserved2 = 1; + + retr = BSP_SD_OK; + } + } + + /* Send dummy byte: 8 Clock pulses of delay */ + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Return the reponse */ + return retr; +} + +/** + * @brief Sends 5 bytes command to the SD card and get response + * @param Cmd: The user expected command to send to SD card. + * @param Arg: The command argument. + * @param Crc: The CRC. + * @param Answer: SD_ANSWER_NOT_EXPECTED or SD_ANSWER_EXPECTED + * @retval SD status + */ +SD_CmdAnswer_typedef SD_SendCmd(uint8_t Cmd, uint32_t Arg, uint8_t Crc, uint8_t Answer) +{ + uint8_t frame[SD_CMD_LENGTH], frameout[SD_CMD_LENGTH]; + SD_CmdAnswer_typedef retr = {0xFF, 0xFF , 0xFF, 0xFF, 0xFF}; + + /* R1 Lenght = NCS(0)+ 6 Bytes command + NCR(min1 max8) + 1 Bytes answer + NEC(0) = 15bytes */ + /* R1b identical to R1 + Busy information */ + /* R2 Lenght = NCS(0)+ 6 Bytes command + NCR(min1 max8) + 2 Bytes answer + NEC(0) = 16bytes */ + + /* Prepare Frame to send */ + frame[0] = (Cmd | 0x40); /* Construct byte 1 */ + frame[1] = (uint8_t)(Arg >> 24); /* Construct byte 2 */ + frame[2] = (uint8_t)(Arg >> 16); /* Construct byte 3 */ + frame[3] = (uint8_t)(Arg >> 8); /* Construct byte 4 */ + frame[4] = (uint8_t)(Arg); /* Construct byte 5 */ + frame[5] = (Crc | 0x01); /* Construct byte 6 */ + + /* Send the command */ + SD_IO_CSState(0); + SD_IO_WriteReadData(frame, frameout, SD_CMD_LENGTH); /* Send the Cmd bytes */ + + switch(Answer) + { + case SD_ANSWER_R1_EXPECTED : + retr.r1 = SD_ReadData(); + break; + case SD_ANSWER_R1B_EXPECTED : + retr.r1 = SD_ReadData(); + retr.r2 = SD_IO_WriteByte(SD_DUMMY_BYTE); + /* Set CS High */ + SD_IO_CSState(1); + HAL_Delay(1); + /* Set CS Low */ + SD_IO_CSState(0); + + /* Wait IO line return 0xFF */ + while (SD_IO_WriteByte(SD_DUMMY_BYTE) != 0xFF); + break; + case SD_ANSWER_R2_EXPECTED : + retr.r1 = SD_ReadData(); + retr.r2 = SD_IO_WriteByte(SD_DUMMY_BYTE); + break; + case SD_ANSWER_R3_EXPECTED : + case SD_ANSWER_R7_EXPECTED : + retr.r1 = SD_ReadData(); + retr.r2 = SD_IO_WriteByte(SD_DUMMY_BYTE); + retr.r3 = SD_IO_WriteByte(SD_DUMMY_BYTE); + retr.r4 = SD_IO_WriteByte(SD_DUMMY_BYTE); + retr.r5 = SD_IO_WriteByte(SD_DUMMY_BYTE); + break; + default : + break; + } + return retr; +} + +/** + * @brief Gets the SD card data response and check the busy flag. + * @param None + * @retval The SD status: Read data response xxx01 + * - status 010: Data accecpted + * - status 101: Data rejected due to a crc error + * - status 110: Data rejected due to a Write error. + * - status 111: Data rejected due to other error. + */ +uint8_t SD_GetDataResponse(void) +{ + uint8_t dataresponse; + uint8_t rvalue = SD_DATA_OTHER_ERROR; + + dataresponse = SD_IO_WriteByte(SD_DUMMY_BYTE); + SD_IO_WriteByte(SD_DUMMY_BYTE); /* read the busy response byte*/ + + /* Mask unused bits */ + switch (dataresponse & 0x1F) + { + case SD_DATA_OK: + rvalue = SD_DATA_OK; + + /* Set CS High */ + SD_IO_CSState(1); + /* Set CS Low */ + SD_IO_CSState(0); + + /* Wait IO line return 0xFF */ + while (SD_IO_WriteByte(SD_DUMMY_BYTE) != 0xFF); + break; + case SD_DATA_CRC_ERROR: + rvalue = SD_DATA_CRC_ERROR; + break; + case SD_DATA_WRITE_ERROR: + rvalue = SD_DATA_WRITE_ERROR; + break; + default: + break; + } + + /* Return response */ + return rvalue; +} + + +/** + * @brief Put the SD in Idle state. + * @param None + * @retval SD status + */ +uint8_t SD_GoIdleState(void) +{ + SD_CmdAnswer_typedef response; + __IO uint8_t counter = 0; + /* Send CMD0 (SD_CMD_GO_IDLE_STATE) to put SD in SPI mode and + wait for In Idle State Response (R1 Format) equal to 0x01 */ + do{ + counter++; + response = SD_SendCmd(SD_CMD_GO_IDLE_STATE, 0, 0x95, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(counter >= SD_MAX_TRY) + { + return BSP_SD_ERROR; + } + } + while(response.r1 != SD_R1_IN_IDLE_STATE); + + + /* Send CMD8 (SD_CMD_SEND_IF_COND) to check the power supply status + and wait until response (R7 Format) equal to 0xAA and */ + response = SD_SendCmd(SD_CMD_SEND_IF_COND, 0x1AA, 0x87, SD_ANSWER_R7_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) + { + /* initialise card V1 */ + do + { + /* initialise card V1 */ + /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_APP_CMD, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Send ACMD41 (SD_CMD_SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + } + while(response.r1 == SD_R1_IN_IDLE_STATE); + flag_SDHC = 0; + } + else if(response.r1 == SD_R1_IN_IDLE_STATE) + { + /* initialise card V2 */ + do { + + /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + + /* Send ACMD41 (SD_CMD_SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x40000000, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + } + while(response.r1 == SD_R1_IN_IDLE_STATE); + + if((response.r1 & SD_R1_ILLEGAL_COMMAND) == SD_R1_ILLEGAL_COMMAND) + { + do { + /* Send CMD55 (SD_CMD_APP_CMD) before any ACMD command: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_APP_CMD, 0, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(response.r1 != SD_R1_IN_IDLE_STATE) + { + return BSP_SD_ERROR; + } + /* Send ACMD41 (SD_CMD_SD_APP_OP_COND) to initialize SDHC or SDXC cards: R1 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_SD_APP_OP_COND, 0x00000000, 0xFF, SD_ANSWER_R1_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + } + while(response.r1 == SD_R1_IN_IDLE_STATE); + } + + /* Send CMD58 (SD_CMD_READ_OCR) to initialize SDHC or SDXC cards: R3 response (0x00: no errors) */ + response = SD_SendCmd(SD_CMD_READ_OCR, 0x00000000, 0xFF, SD_ANSWER_R3_EXPECTED); + SD_IO_CSState(1); + SD_IO_WriteByte(SD_DUMMY_BYTE); + if(response.r1 != SD_R1_NO_ERROR) + { + return BSP_SD_ERROR; + } + flag_SDHC = (response.r2 & 0x40) >> 6; + } + else + { + return BSP_SD_ERROR; + } + + return BSP_SD_OK; +} + +/** + * @brief Waits a data until a value different from SD_DUMMY_BITE + * @param None + * @retval the value read + */ +uint8_t SD_ReadData(void) +{ + uint8_t timeout = 0x08; + uint8_t readvalue; + + /* Check if response is got or a timeout is happen */ + do { + readvalue = SD_IO_WriteByte(SD_DUMMY_BYTE); + timeout--; + + }while ((readvalue == SD_DUMMY_BYTE) && timeout); + + /* Right response got */ + return readvalue; +} + +/** + * @brief Waits a data from the SD card + * @param data : Expected data from the SD card + * @retval BSP_SD_OK or BSP_SD_TIMEOUT + */ +uint8_t SD_WaitData(uint8_t data) +{ + uint16_t timeout = 0xFFFF; + uint8_t readvalue; + + /* Check if response is got or a timeout is happen */ + + do { + readvalue = SD_IO_WriteByte(SD_DUMMY_BYTE); + timeout--; + }while ((readvalue != data) && timeout); + + if (timeout == 0) + { + /* After time out */ + return BSP_SD_TIMEOUT; + } + + /* Right response got */ + return BSP_SD_OK; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_sd.h b/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_sd.h new file mode 100644 index 00000000..60b5b11f --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Adafruit_Shield/stm32_adafruit_sd.h @@ -0,0 +1,247 @@ +/** + ****************************************************************************** + * @file stm32_adafruit_sd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32_adafruit_sd.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32_ADAFRUIT_SD_H +#define __STM32_ADAFRUIT_SD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include + +/** @addtogroup BSP + * @{ + */ +#define __IO volatile + +/** @addtogroup STM32_ADAFRUIT + * @{ + */ + +/** @defgroup STM32_ADAFRUIT_SD + * @{ + */ + +/** @defgroup STM32_ADAFRUIT_SD_Exported_Types + * @{ + */ + +/** + * @brief SD status structure definition + */ +enum { + BSP_SD_OK = 0x00, + MSD_OK = 0x00, + BSP_SD_ERROR = 0x01, + BSP_SD_TIMEOUT +}; + +typedef struct +{ + uint8_t Reserved1:2; /* Reserved */ + uint16_t DeviceSize:12; /* Device Size */ + uint8_t MaxRdCurrentVDDMin:3; /* Max. read current @ VDD min */ + uint8_t MaxRdCurrentVDDMax:3; /* Max. read current @ VDD max */ + uint8_t MaxWrCurrentVDDMin:3; /* Max. write current @ VDD min */ + uint8_t MaxWrCurrentVDDMax:3; /* Max. write current @ VDD max */ + uint8_t DeviceSizeMul:3; /* Device size multiplier */ +} struct_v1; + + +typedef struct +{ + uint8_t Reserved1:6; /* Reserved */ + uint32_t DeviceSize:22; /* Device Size */ + uint8_t Reserved2:1; /* Reserved */ +} struct_v2; + +/** + * @brief Card Specific Data: CSD Register + */ +typedef struct +{ + /* Header part */ + uint8_t CSDStruct:2; /* CSD structure */ + uint8_t Reserved1:6; /* Reserved */ + uint8_t TAAC:8; /* Data read access-time 1 */ + uint8_t NSAC:8; /* Data read access-time 2 in CLK cycles */ + uint8_t MaxBusClkFrec:8; /* Max. bus clock frequency */ + uint16_t CardComdClasses:12; /* Card command classes */ + uint8_t RdBlockLen:4; /* Max. read data block length */ + uint8_t PartBlockRead:1; /* Partial blocks for read allowed */ + uint8_t WrBlockMisalign:1; /* Write block misalignment */ + uint8_t RdBlockMisalign:1; /* Read block misalignment */ + uint8_t DSRImpl:1; /* DSR implemented */ + + /* v1 or v2 struct */ + union csd_version { + struct_v1 v1; + struct_v2 v2; + } version; + + uint8_t EraseSingleBlockEnable:1; /* Erase single block enable */ + uint8_t EraseSectorSize:7; /* Erase group size multiplier */ + uint8_t WrProtectGrSize:7; /* Write protect group size */ + uint8_t WrProtectGrEnable:1; /* Write protect group enable */ + uint8_t Reserved2:2; /* Reserved */ + uint8_t WrSpeedFact:3; /* Write speed factor */ + uint8_t MaxWrBlockLen:4; /* Max. write data block length */ + uint8_t WriteBlockPartial:1; /* Partial blocks for write allowed */ + uint8_t Reserved3:5; /* Reserved */ + uint8_t FileFormatGrouop:1; /* File format group */ + uint8_t CopyFlag:1; /* Copy flag (OTP) */ + uint8_t PermWrProtect:1; /* Permanent write protection */ + uint8_t TempWrProtect:1; /* Temporary write protection */ + uint8_t FileFormat:2; /* File Format */ + uint8_t Reserved4:2; /* Reserved */ + uint8_t crc:7; /* Reserved */ + uint8_t Reserved5:1; /* always 1*/ + +} SD_CSD; + +/** + * @brief Card Identification Data: CID Register + */ +typedef struct +{ + __IO uint8_t ManufacturerID; /* ManufacturerID */ + __IO uint16_t OEM_AppliID; /* OEM/Application ID */ + __IO uint32_t ProdName1; /* Product Name part1 */ + __IO uint8_t ProdName2; /* Product Name part2*/ + __IO uint8_t ProdRev; /* Product Revision */ + __IO uint32_t ProdSN; /* Product Serial Number */ + __IO uint8_t Reserved1; /* Reserved1 */ + __IO uint16_t ManufactDate; /* Manufacturing Date */ + __IO uint8_t CID_CRC; /* CID CRC */ + __IO uint8_t Reserved2; /* always 1 */ +} SD_CID; + +/** + * @brief SD Card information + */ +typedef struct +{ + SD_CSD Csd; + SD_CID Cid; + uint32_t CardCapacity; /*!< Card Capacity */ + uint32_t CardBlockSize; /*!< Card Block Size */ + uint32_t LogBlockNbr; /*!< Specifies the Card logical Capacity in blocks */ + uint32_t LogBlockSize; /*!< Specifies logical block size in bytes */ +} SD_CardInfo; + +/** + * @} + */ + +/** @defgroup STM32_ADAFRUIT_SPI_SD_Exported_Constants + * @{ + */ + +/** + * @brief Block Size + */ +#define SD_BLOCK_SIZE 0x200 + +/** + * @brief SD detection on its memory slot + */ +#define SD_PRESENT ((uint8_t)0x01) +#define SD_NOT_PRESENT ((uint8_t)0x00) + +#define SD_DATATIMEOUT ((uint32_t)100000000) + +/** + * @brief SD Card information structure + */ +#define BSP_SD_CardInfo SD_CardInfo + +/** + * @} + */ + +/** @defgroup STM32_ADAFRUIT_SD_Exported_Macro + * @{ + */ + +/** + * @} + */ + +/** @defgroup STM32_ADAFRUIT_SD_Exported_Functions + * @{ + */ +uint8_t BSP_SD_Init(void); +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); +uint8_t BSP_SD_GetCardState(void); +uint8_t BSP_SD_GetCardInfo(SD_CardInfo *pCardInfo); + +/* Link functions for SD Card peripheral*/ +void SD_IO_Init(void); +void SD_IO_CSState(uint8_t state); +void SD_IO_WriteReadData(const uint8_t *DataIn, uint8_t *DataOut, uint16_t DataLength); +uint8_t SD_IO_WriteByte(uint8_t Data); + +/* Link function for HAL delay */ +void HAL_Delay(__IO uint32_t Delay); + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32_ADAFRUIT_SD_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/Common/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/Common/Release_Notes.html new file mode 100644 index 00000000..e173ae53 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/Common/Release_Notes.html @@ -0,0 +1,759 @@ + + + + + + + + + + + + + + + + + + + + + Release Notes for BSP Components Common Drivers + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+ +

Release +Notes for BSP Components Common  Drivers

+ +

Copyright +2015 STMicroelectronics

+

+
+

 

+ + + + + + +
+ + +

Update History

+

V4.0.1 / 21-July-2015

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • tsensor.h: Fix compilation issue on TSENSOR_InitTypeDef

V4.0.0 / 22-June-2015

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • accelero.h: add *DeInit field in ACCELERO_DrvTypeDef structure
  • audio.h: add *DeInit field in AUDIO_DrvTypeDef structure
  • idd.h: 
    • add Shunt0StabDelay, Shunt1StabDelay, Shunt2StabDelay, Shunt3StabDelay, Shunt4StabDelay and ShuntNbOnBoard fields in IDD_ConfigTypeDef structure
    • rename ShuntNumber field to ShuntNbUsed in IDD_ConfigTypeDef structure
  • magneto.h: add *DeInit field in MAGNETO_DrvTypeDef structure
  • Important Note:  this release V4.0.0 is not backward compatible with V3.0.0

V3.0.0 / 28-April-2015

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • accelero.h: add *LowPower field in ACCELERO_DrvTypeDef structure
  • magneto.h: add *LowPower field in MAGNETO_DrvTypeDef structure
  • gyro.h: add *DeInit and *LowPower fields in GYRO_DrvTypeDef structure
  • camera.h: add CAMERA_COLOR_EFFECT_NONE define
  • idd.h: 
    • add MeasureNb, DeltaDelayUnit and DeltaDelayValue fields in IDD_ConfigTypeDef structure
    • rename PreDelay field to PreDelayUnit in IDD_ConfigTypeDef structure
    +
  • Important Note:  this release V3.0.0 is not backward compatible with V2.2.0
    +
  • +

V2.2.0 / 09-February-2015

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • Magnetometer driver function prototypes added (magneto.h file)
  • Update "idd.h" file to provide DeInit() and WakeUp() services in IDD current measurement driver

V2.1.0 / 06-February-2015

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • IDD current measurement driver function prototypes added (idd.h file)
  • io.h: add new typedef enum IO_PinState with IO_PIN_RESET and IO_PIN_SET values

V2.0.0 / 15-December-2014

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • Update "io.h" file to support MFX (Multi Function eXpander) device available on some STM32 boards
    • add new entries for IO_ModeTypedef enumeration structure
    • update the IO_DrvTypeDef structure
      • Update all return values and function parameters to uint32_t
      • Add a return value for Config field
  • Important Note:  this version V2.0.0 is not backward compatible with V1.2.1

V1.2.1 / 02-December-2014

+

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • gyro.h: change “__GIRO_H” by “__GYRO_H” to fix compilation issue under Mac OS

V1.2.0 / 18-June-2014

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • EPD (E Paper Display)  driver function prototype added (epd.h file)
    +

V1.1.0 / 21-March-2014

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • Temperature Sensor driver function prototype added

V1.0.0 / 18-February-2014

+ + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • First official release with  Accelerometer, Audio, Camera, Gyroscope, IO, LCD and Touch Screen drivers function prototypes

License

+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/Common/accelero.h b/src/port_stm32f7/common/bsp_drivers/Components/Common/accelero.h new file mode 100644 index 00000000..0de82329 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/Common/accelero.h @@ -0,0 +1,143 @@ +/** + ****************************************************************************** + * @file accelero.h + * @author MCD Application Team + * @version V4.0.1 + * @date 21-July-2015 + * @brief This header file contains the functions prototypes for the Accelerometer driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __ACCELERO_H +#define __ACCELERO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup ACCELERO + * @{ + */ + +/** @defgroup ACCELERO_Exported_Types + * @{ + */ + +/** @defgroup ACCELERO_Driver_structure Accelerometer Driver structure + * @{ + */ +typedef struct +{ + void (*Init)(uint16_t); + void (*DeInit)(void); + uint8_t (*ReadID)(void); + void (*Reset)(void); + void (*LowPower)(void); + void (*ConfigIT)(void); + void (*EnableIT)(uint8_t); + void (*DisableIT)(uint8_t); + uint8_t (*ITStatus)(uint16_t); + void (*ClearIT)(void); + void (*FilterConfig)(uint8_t); + void (*FilterCmd)(uint8_t); + void (*GetXYZ)(int16_t *); +}ACCELERO_DrvTypeDef; +/** + * @} + */ + +/** @defgroup ACCELERO_Configuration_structure Accelerometer Configuration structure + * @{ + */ + +/* ACCELERO struct */ +typedef struct +{ + uint8_t Power_Mode; /* Power-down/Normal Mode */ + uint8_t AccOutput_DataRate; /* OUT data rate */ + uint8_t Axes_Enable; /* Axes enable */ + uint8_t High_Resolution; /* High Resolution enabling/disabling */ + uint8_t BlockData_Update; /* Block Data Update */ + uint8_t Endianness; /* Endian Data selection */ + uint8_t AccFull_Scale; /* Full Scale selection */ + uint8_t Communication_Mode; +}ACCELERO_InitTypeDef; + +/* ACCELERO High Pass Filter struct */ +typedef struct +{ + uint8_t HighPassFilter_Mode_Selection; /* Internal filter mode */ + uint8_t HighPassFilter_CutOff_Frequency; /* High pass filter cut-off frequency */ + uint8_t HighPassFilter_AOI1; /* HPF_enabling/disabling for AOI function on interrupt 1 */ + uint8_t HighPassFilter_AOI2; /* HPF_enabling/disabling for AOI function on interrupt 2 */ + uint8_t HighPassFilter_Data_Sel; + uint8_t HighPassFilter_Stat; +}ACCELERO_FilterConfigTypeDef; + +/** + * @} + */ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ACCELERO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/Common/audio.h b/src/port_stm32f7/common/bsp_drivers/Components/Common/audio.h new file mode 100644 index 00000000..8b93673f --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/Common/audio.h @@ -0,0 +1,122 @@ +/** + ****************************************************************************** + * @file audio.h + * @author MCD Application Team + * @version V4.0.1 + * @date 21-July-2015 + * @brief This header file contains the common defines and functions prototypes + * for the Audio driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __AUDIO_H +#define __AUDIO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup AUDIO + * @{ + */ + +/** @defgroup AUDIO_Exported_Constants + * @{ + */ + +/* Codec audio Standards */ +#define CODEC_STANDARD 0x04 +#define I2S_STANDARD I2S_STANDARD_PHILIPS + +/** + * @} + */ + +/** @defgroup AUDIO_Exported_Types + * @{ + */ + +/** @defgroup AUDIO_Driver_structure Audio Driver structure + * @{ + */ +typedef struct +{ + uint32_t (*Init)(uint16_t, uint16_t, uint8_t, uint32_t); + void (*DeInit)(void); + uint32_t (*ReadID)(uint16_t); + uint32_t (*Play)(uint16_t, uint16_t*, uint16_t); + uint32_t (*Pause)(uint16_t); + uint32_t (*Resume)(uint16_t); + uint32_t (*Stop)(uint16_t, uint32_t); + uint32_t (*SetFrequency)(uint16_t, uint32_t); + uint32_t (*SetVolume)(uint16_t, uint8_t); + uint32_t (*SetMute)(uint16_t, uint32_t); + uint32_t (*SetOutputMode)(uint16_t, uint8_t); + uint32_t (*Reset)(uint16_t); +}AUDIO_DrvTypeDef; +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __AUDIO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/Common/camera.h b/src/port_stm32f7/common/bsp_drivers/Components/Common/camera.h new file mode 100644 index 00000000..c64f32fd --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/Common/camera.h @@ -0,0 +1,141 @@ +/** + ****************************************************************************** + * @file camera.h + * @author MCD Application Team + * @version V4.0.1 + * @date 21-July-2015 + * @brief This header file contains the common defines and functions prototypes + * for the camera driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __CAMERA_H +#define __CAMERA_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup CAMERA + * @{ + */ + + +/** @defgroup CAMERA_Exported_Types + * @{ + */ + +/** @defgroup CAMERA_Driver_structure Camera Driver structure + * @{ + */ +typedef struct +{ + void (*Init)(uint16_t, uint32_t); + uint16_t (*ReadID)(uint16_t); + void (*Config)(uint16_t, uint32_t, uint32_t, uint32_t); +}CAMERA_DrvTypeDef; +/** + * @} + */ + +/** + * @} + */ + +/** @defgroup CAMERA_Exported_Constants + * @{ + */ +#define CAMERA_R160x120 0x00 /* QQVGA Resolution */ +#define CAMERA_R320x240 0x01 /* QVGA Resolution */ +#define CAMERA_R480x272 0x02 /* 480x272 Resolution */ +#define CAMERA_R640x480 0x03 /* VGA Resolution */ + +#define CAMERA_CONTRAST_BRIGHTNESS 0x00 /* Camera contrast brightness features */ +#define CAMERA_BLACK_WHITE 0x01 /* Camera black white feature */ +#define CAMERA_COLOR_EFFECT 0x03 /* Camera color effect feature */ + +#define CAMERA_BRIGHTNESS_LEVEL0 0x00 /* Brightness level -2 */ +#define CAMERA_BRIGHTNESS_LEVEL1 0x01 /* Brightness level -1 */ +#define CAMERA_BRIGHTNESS_LEVEL2 0x02 /* Brightness level 0 */ +#define CAMERA_BRIGHTNESS_LEVEL3 0x03 /* Brightness level +1 */ +#define CAMERA_BRIGHTNESS_LEVEL4 0x04 /* Brightness level +2 */ + +#define CAMERA_CONTRAST_LEVEL0 0x05 /* Contrast level -2 */ +#define CAMERA_CONTRAST_LEVEL1 0x06 /* Contrast level -1 */ +#define CAMERA_CONTRAST_LEVEL2 0x07 /* Contrast level 0 */ +#define CAMERA_CONTRAST_LEVEL3 0x08 /* Contrast level +1 */ +#define CAMERA_CONTRAST_LEVEL4 0x09 /* Contrast level +2 */ + +#define CAMERA_BLACK_WHITE_BW 0x00 /* Black and white effect */ +#define CAMERA_BLACK_WHITE_NEGATIVE 0x01 /* Negative effect */ +#define CAMERA_BLACK_WHITE_BW_NEGATIVE 0x02 /* BW and Negative effect */ +#define CAMERA_BLACK_WHITE_NORMAL 0x03 /* Normal effect */ + +#define CAMERA_COLOR_EFFECT_NONE 0x00 /* No effects */ +#define CAMERA_COLOR_EFFECT_BLUE 0x01 /* Blue effect */ +#define CAMERA_COLOR_EFFECT_GREEN 0x02 /* Green effect */ +#define CAMERA_COLOR_EFFECT_RED 0x03 /* Red effect */ +#define CAMERA_COLOR_EFFECT_ANTIQUE 0x04 /* Antique effect */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __CAMERA_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/Common/epd.h b/src/port_stm32f7/common/bsp_drivers/Components/Common/epd.h new file mode 100644 index 00000000..a06be10d --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/Common/epd.h @@ -0,0 +1,115 @@ +/** + ****************************************************************************** + * @file epd.h + * @author MCD Application Team + * @version V4.0.1 + * @date 21-July-2015 + * @brief This file contains all the functions prototypes for the + * EPD (E Paper Display) driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __EPD_H +#define __EPD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup Common + * @{ + */ + +/** @addtogroup EPD + * @{ + */ + +/** @defgroup EPD_Exported_Types + * @{ + */ + +/** @defgroup EPD_Driver_structure E Paper Display Driver structure + * @{ + */ +typedef struct +{ + void (*Init)(void); + void (*WritePixel)(uint8_t); + + /* Optimized operation */ + void (*SetDisplayWindow)(uint16_t, uint16_t, uint16_t, uint16_t); + void (*RefreshDisplay)(void); + void (*CloseChargePump)(void); + + uint16_t (*GetEpdPixelWidth)(void); + uint16_t (*GetEpdPixelHeight)(void); + void (*DrawImage)(uint16_t, uint16_t, uint16_t, uint16_t, uint8_t*); +} +EPD_DrvTypeDef; +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* EPD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/Common/gyro.h b/src/port_stm32f7/common/bsp_drivers/Components/Common/gyro.h new file mode 100644 index 00000000..462928c9 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/Common/gyro.h @@ -0,0 +1,145 @@ +/** + ****************************************************************************** + * @file gyro.h + * @author MCD Application Team + * @version V4.0.1 + * @date 21-July-2015 + * @brief This header file contains the functions prototypes for the gyroscope driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __GYRO_H +#define __GYRO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup GYRO + * @{ + */ + +/** @defgroup GYRO_Exported_Types + * @{ + */ + +/** @defgroup GYRO_Driver_structure Gyroscope Driver structure + * @{ + */ +typedef struct +{ + void (*Init)(uint16_t); + void (*DeInit)(void); + uint8_t (*ReadID)(void); + void (*Reset)(void); + void (*LowPower)(uint16_t); + void (*ConfigIT)(uint16_t); + void (*EnableIT)(uint8_t); + void (*DisableIT)(uint8_t); + uint8_t (*ITStatus)(uint16_t, uint16_t); + void (*ClearIT)(uint16_t, uint16_t); + void (*FilterConfig)(uint8_t); + void (*FilterCmd)(uint8_t); + void (*GetXYZ)(float *); +}GYRO_DrvTypeDef; +/** + * @} + */ + +/** @defgroup GYRO_Config_structure Gyroscope Configuration structure + * @{ + */ + +typedef struct +{ + uint8_t Power_Mode; /* Power-down/Sleep/Normal Mode */ + uint8_t Output_DataRate; /* OUT data rate */ + uint8_t Axes_Enable; /* Axes enable */ + uint8_t Band_Width; /* Bandwidth selection */ + uint8_t BlockData_Update; /* Block Data Update */ + uint8_t Endianness; /* Endian Data selection */ + uint8_t Full_Scale; /* Full Scale selection */ +}GYRO_InitTypeDef; + +/* GYRO High Pass Filter struct */ +typedef struct +{ + uint8_t HighPassFilter_Mode_Selection; /* Internal filter mode */ + uint8_t HighPassFilter_CutOff_Frequency; /* High pass filter cut-off frequency */ +}GYRO_FilterConfigTypeDef; + +/*GYRO Interrupt struct */ +typedef struct +{ + uint8_t Latch_Request; /* Latch interrupt request into CLICK_SRC register */ + uint8_t Interrupt_Axes; /* X, Y, Z Axes Interrupts */ + uint8_t Interrupt_ActiveEdge; /* Interrupt Active edge */ +}GYRO_InterruptConfigTypeDef; + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __GYRO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/Common/idd.h b/src/port_stm32f7/common/bsp_drivers/Components/Common/idd.h new file mode 100644 index 00000000..1b8a762e --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/Common/idd.h @@ -0,0 +1,168 @@ +/** + ****************************************************************************** + * @file idd.h + * @author MCD Application Team + * @version V4.0.1 + * @date 21-July-2015 + * @brief This file contains all the functions prototypes for the IDD driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __IDD_H +#define __IDD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup IDD + * @{ + */ + +/** @defgroup IDD_Exported_Types IDD Exported Types + * @{ + */ + +/** @defgroup IDD_Config_structure IDD Configuration structure + * @{ + */ +typedef struct +{ + uint16_t AmpliGain; /*!< Specifies ampli gain value + */ + uint16_t VddMin; /*!< Specifies minimum MCU VDD can reach to protect MCU from reset + */ + uint16_t Shunt0Value; /*!< Specifies value of Shunt 0 if existing + */ + uint16_t Shunt1Value; /*!< Specifies value of Shunt 1 if existing + */ + uint16_t Shunt2Value; /*!< Specifies value of Shunt 2 if existing + */ + uint16_t Shunt3Value; /*!< Specifies value of Shunt 3 if existing + */ + uint16_t Shunt4Value; /*!< Specifies value of Shunt 4 if existing + */ + uint16_t Shunt0StabDelay; /*!< Specifies delay of Shunt 0 stabilization if existing + */ + uint16_t Shunt1StabDelay; /*!< Specifies delay of Shunt 1 stabilization if existing + */ + uint16_t Shunt2StabDelay; /*!< Specifies delay of Shunt 2 stabilization if existing + */ + uint16_t Shunt3StabDelay; /*!< Specifies delay of Shunt 3 stabilization if existing + */ + uint16_t Shunt4StabDelay; /*!< Specifies delay of Shunt 4 stabilization if existing + */ + uint8_t ShuntNbOnBoard; /*!< Specifies number of shunts that are present on board + This parameter can be a value of @ref IDD_shunt_number */ + uint8_t ShuntNbUsed; /*!< Specifies number of shunts used for measurement + This parameter can be a value of @ref IDD_shunt_number */ + uint8_t VrefMeasurement; /*!< Specifies if Vref is automatically measured before each Idd measurement + This parameter can be a value of @ref IDD_Vref_Measurement */ + uint8_t Calibration; /*!< Specifies if calibration is done before each Idd measurement + */ + uint8_t PreDelayUnit; /*!< Specifies Pre delay unit + This parameter can be a value of @ref IDD_PreDelay */ + uint8_t PreDelayValue; /*!< Specifies Pre delay value in selected unit + */ + uint8_t MeasureNb; /*!< Specifies number of Measure to be performed + This parameter can be a value between 1 and 256 */ + uint8_t DeltaDelayUnit; /*!< Specifies Delta delay unit + This parameter can be a value of @ref IDD_DeltaDelay */ + uint8_t DeltaDelayValue; /*!< Specifies Delta delay between 2 measures + value can be between 1 and 128 */ +}IDD_ConfigTypeDef; +/** + * @} + */ + +/** @defgroup IDD_Driver_structure IDD Driver structure + * @{ + */ +typedef struct +{ + void (*Init)(uint16_t); + void (*DeInit)(uint16_t); + uint16_t (*ReadID)(uint16_t); + void (*Reset)(uint16_t); + void (*LowPower)(uint16_t); + void (*WakeUp)(uint16_t); + void (*Start)(uint16_t); + void (*Config)(uint16_t,IDD_ConfigTypeDef); + void (*GetValue)(uint16_t, uint32_t *); + void (*EnableIT)(uint16_t); + void (*ClearIT)(uint16_t); + uint8_t (*GetITStatus)(uint16_t); + void (*DisableIT)(uint16_t); + void (*ErrorEnableIT)(uint16_t); + void (*ErrorClearIT)(uint16_t); + uint8_t (*ErrorGetITStatus)(uint16_t); + void (*ErrorDisableIT)(uint16_t); + uint8_t (*ErrorGetSrc)(uint16_t); + uint8_t (*ErrorGetCode)(uint16_t); +}IDD_DrvTypeDef; +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __IDD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/Common/io.h b/src/port_stm32f7/common/bsp_drivers/Components/Common/io.h new file mode 100644 index 00000000..b33c00e6 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/Common/io.h @@ -0,0 +1,150 @@ +/** + ****************************************************************************** + * @file io.h + * @author MCD Application Team + * @version V4.0.1 + * @date 21-July-2015 + * @brief This file contains all the functions prototypes for the IO driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __IO_H +#define __IO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup IO + * @{ + */ + +/** @defgroup IO_Exported_Types + * @{ + */ + +/** + * @brief IO Bit SET and Bit RESET enumeration + */ +typedef enum +{ + IO_PIN_RESET = 0, + IO_PIN_SET +}IO_PinState; + +typedef enum +{ + IO_MODE_INPUT = 0, /* input floating */ + IO_MODE_OUTPUT, /* output Push Pull */ + IO_MODE_IT_RISING_EDGE, /* float input - irq detect on rising edge */ + IO_MODE_IT_FALLING_EDGE, /* float input - irq detect on falling edge */ + IO_MODE_IT_LOW_LEVEL, /* float input - irq detect on low level */ + IO_MODE_IT_HIGH_LEVEL, /* float input - irq detect on high level */ + /* following modes only available on MFX*/ + IO_MODE_ANALOG, /* analog mode */ + IO_MODE_OFF, /* when pin isn't used*/ + IO_MODE_INPUT_PU, /* input with internal pull up resistor */ + IO_MODE_INPUT_PD, /* input with internal pull down resistor */ + IO_MODE_OUTPUT_OD, /* Open Drain output without internal resistor */ + IO_MODE_OUTPUT_OD_PU, /* Open Drain output with internal pullup resistor */ + IO_MODE_OUTPUT_OD_PD, /* Open Drain output with internal pulldown resistor */ + IO_MODE_OUTPUT_PP, /* PushPull output without internal resistor */ + IO_MODE_OUTPUT_PP_PU, /* PushPull output with internal pullup resistor */ + IO_MODE_OUTPUT_PP_PD, /* PushPull output with internal pulldown resistor */ + IO_MODE_IT_RISING_EDGE_PU, /* push up resistor input - irq on rising edge */ + IO_MODE_IT_RISING_EDGE_PD, /* push dw resistor input - irq on rising edge */ + IO_MODE_IT_FALLING_EDGE_PU, /* push up resistor input - irq on falling edge */ + IO_MODE_IT_FALLING_EDGE_PD, /* push dw resistor input - irq on falling edge */ + IO_MODE_IT_LOW_LEVEL_PU, /* push up resistor input - irq detect on low level */ + IO_MODE_IT_LOW_LEVEL_PD, /* push dw resistor input - irq detect on low level */ + IO_MODE_IT_HIGH_LEVEL_PU, /* push up resistor input - irq detect on high level */ + IO_MODE_IT_HIGH_LEVEL_PD, /* push dw resistor input - irq detect on high level */ + +}IO_ModeTypedef; + +/** @defgroup IO_Driver_structure IO Driver structure + * @{ + */ +typedef struct +{ + void (*Init)(uint16_t); + uint16_t (*ReadID)(uint16_t); + void (*Reset)(uint16_t); + + void (*Start)(uint16_t, uint32_t); + uint8_t (*Config)(uint16_t, uint32_t, IO_ModeTypedef); + void (*WritePin)(uint16_t, uint32_t, uint8_t); + uint32_t (*ReadPin)(uint16_t, uint32_t); + + void (*EnableIT)(uint16_t); + void (*DisableIT)(uint16_t); + uint32_t (*ITStatus)(uint16_t, uint32_t); + void (*ClearIT)(uint16_t, uint32_t); + +}IO_DrvTypeDef; +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __IO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/Common/lcd.h b/src/port_stm32f7/common/bsp_drivers/Components/Common/lcd.h new file mode 100644 index 00000000..9ff398b4 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/Common/lcd.h @@ -0,0 +1,114 @@ +/** + ****************************************************************************** + * @file lcd.h + * @author MCD Application Team + * @version V4.0.1 + * @date 21-July-2015 + * @brief This file contains all the functions prototypes for the LCD driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __LCD_H +#define __LCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup LCD + * @{ + */ + +/** @defgroup LCD_Exported_Types + * @{ + */ + +/** @defgroup LCD_Driver_structure LCD Driver structure + * @{ + */ +typedef struct +{ + void (*Init)(void); + uint16_t (*ReadID)(void); + void (*DisplayOn)(void); + void (*DisplayOff)(void); + void (*SetCursor)(uint16_t, uint16_t); + void (*WritePixel)(uint16_t, uint16_t, uint16_t); + uint16_t (*ReadPixel)(uint16_t, uint16_t); + + /* Optimized operation */ + void (*SetDisplayWindow)(uint16_t, uint16_t, uint16_t, uint16_t); + void (*DrawHLine)(uint16_t, uint16_t, uint16_t, uint16_t); + void (*DrawVLine)(uint16_t, uint16_t, uint16_t, uint16_t); + + uint16_t (*GetLcdPixelWidth)(void); + uint16_t (*GetLcdPixelHeight)(void); + void (*DrawBitmap)(uint16_t, uint16_t, uint8_t*); + void (*DrawRGBImage)(uint16_t, uint16_t, uint16_t, uint16_t, uint8_t*); +}LCD_DrvTypeDef; +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LCD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/Common/magneto.h b/src/port_stm32f7/common/bsp_drivers/Components/Common/magneto.h new file mode 100644 index 00000000..dc27dd03 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/Common/magneto.h @@ -0,0 +1,125 @@ +/** + ****************************************************************************** + * @file magneto.h + * @author MCD Application Team + * @version V4.0.1 + * @date 21-July-2015 + * @brief This header file contains the functions prototypes for the MAGNETO driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MAGNETO_H +#define __MAGNETO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup MAGNETO + * @{ + */ + +/** @defgroup MAGNETO_Exported_Types + * @{ + */ + +/** @defgroup MAGNETO_Config_structure Magnetometer Configuration structure + * @{ + */ +typedef struct +{ + uint8_t Register1; + uint8_t Register2; + uint8_t Register3; + uint8_t Register4; + uint8_t Register5; +}MAGNETO_InitTypeDef; +/** + * @} + */ + +/** @defgroup MAGNETO_Driver_structure Magnetometer Driver structure + * @{ + */ +typedef struct +{ + void (*Init)(MAGNETO_InitTypeDef); + void (*DeInit)(void); + uint8_t (*ReadID)(void); + void (*Reset)(void); + void (*LowPower)(void); + void (*ConfigIT)(void); + void (*EnableIT)(uint8_t); + void (*DisableIT)(uint8_t); + uint8_t (*ITStatus)(uint16_t); + void (*ClearIT)(void); + void (*FilterConfig)(uint8_t); + void (*FilterCmd)(uint8_t); + void (*GetXYZ)(int16_t *); +}MAGNETO_DrvTypeDef; +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __MAGNETO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/Common/ts.h b/src/port_stm32f7/common/bsp_drivers/Components/Common/ts.h new file mode 100644 index 00000000..73705964 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/Common/ts.h @@ -0,0 +1,107 @@ +/** + ****************************************************************************** + * @file ts.h + * @author MCD Application Team + * @version V4.0.1 + * @date 21-July-2015 + * @brief This file contains all the functions prototypes for the Touch Screen driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __TS_H +#define __TS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup TS + * @{ + */ + +/** @defgroup TS_Exported_Types + * @{ + */ + +/** @defgroup TS_Driver_structure Touch Sensor Driver structure + * @{ + */ +typedef struct +{ + void (*Init)(uint16_t); + uint16_t (*ReadID)(uint16_t); + void (*Reset)(uint16_t); + void (*Start)(uint16_t); + uint8_t (*DetectTouch)(uint16_t); + void (*GetXY)(uint16_t, uint16_t*, uint16_t*); + void (*EnableIT)(uint16_t); + void (*ClearIT)(uint16_t); + uint8_t (*GetITStatus)(uint16_t); + void (*DisableIT)(uint16_t); +}TS_DrvTypeDef; +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __TS_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/Common/tsensor.h b/src/port_stm32f7/common/bsp_drivers/Components/Common/tsensor.h new file mode 100644 index 00000000..4ea0ffc2 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/Common/tsensor.h @@ -0,0 +1,118 @@ +/** + ****************************************************************************** + * @file tsensor.h + * @author MCD Application Team + * @version V4.0.1 + * @date 21-July-2015 + * @brief This header file contains the functions prototypes for the + * Temperature Sensor driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __TSENSOR_H +#define __TSENSOR_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup TSENSOR + * @{ + */ + +/** @defgroup TSENSOR_Exported_Types + * @{ + */ + +/** @defgroup TSENSOR_Config_structure Temperature Sensor Configuration structure + * @{ + */ +typedef struct +{ + uint8_t AlertMode; /* Alert Mode Temperature out of range*/ + uint8_t ConversionMode; /* Continuous/One Shot Mode */ + uint8_t ConversionResolution; /* Temperature Resolution */ + uint8_t ConversionRate; /* Number of measure per second */ + uint8_t TemperatureLimitHigh; /* High Temperature Limit Range */ + uint8_t TemperatureLimitLow; /* Low Temperature Limit Range */ +}TSENSOR_InitTypeDef; +/** + * @} + */ + +/** @defgroup TSENSOR_Driver_structure Temperature Sensor Driver structure + * @{ + */ +typedef struct +{ + void (*Init)(uint16_t, TSENSOR_InitTypeDef *); + uint8_t (*IsReady)(uint16_t, uint32_t); + uint8_t (*ReadStatus)(uint16_t); + uint16_t (*ReadTemp)(uint16_t); +}TSENSOR_DrvTypeDef; +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __TSENSOR_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/adv7533/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/adv7533/Release_Notes.html new file mode 100644 index 00000000..03a5dacf --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/adv7533/Release_Notes.html @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + Release Notes for STM32 BSP Components Drivers + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for ADV7533 Component Driver

+

Copyright +2017 STMicroelectronics

+

+
+

 

+ + + + + + +

Update History

+

V1.0.2 +/ 07-April-2017

+

Main +Changes

+ + + + + + + + + + + + +
    +
  • Update comments to be used for PDSC generation
    +
  • +
+ +

V1.0.1 +/ 05-December-2016

+ + + +

Main +Changes

+ + + + + + + + + + +
    +
  • Add adv7533_SetVolume, adv7533_SetOutputMode and adv7533_Reset to adv7533_drv for compatibility reasons
  • +
+

V1.0.0 +/ 26-August-2016

+ +

Main +Changes

+ + + + + + + + + +
  • First official release of ADV7533 HDMI component driver
    +

License

+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+
For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32
+

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/adv7533/adv7533.c b/src/port_stm32f7/common/bsp_drivers/Components/adv7533/adv7533.c new file mode 100644 index 00000000..aee24e5c --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/adv7533/adv7533.c @@ -0,0 +1,511 @@ +/** + ****************************************************************************** + * @file adv7533.c + * @author MCD Application Team + * @brief This file provides the ADV7533 DSI to HDMI bridge driver + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "adv7533.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @defgroup ADV7533 ADV7533 + * @brief This file provides a set of functions needed to drive the + * adv7533 DSI-HDMI bridge. + * @{ + */ + +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private constants ---------------------------------------------------------*/ +/** @defgroup ADV7533_Private_Constants ADV7533 Private Constants + * @{ + */ + +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ +/** @defgroup ADV7533_Exported_Variables + * @{ + */ + +AUDIO_DrvTypeDef adv7533_drv = +{ + adv7533_AudioInit, + adv7533_DeInit, + adv7533_ReadID, + adv7533_Play, + adv7533_Pause, + adv7533_Resume, + adv7533_Stop, + adv7533_SetFrequency, + adv7533_SetVolume, /* Not supported, added for compatibility */ + adv7533_SetMute, + adv7533_SetOutputMode, /* Not supported, added for compatibility */ + adv7533_Reset /* Not supported, added for compatibility */ +}; + +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ +/** @defgroup ADV7533_Exported_Functions ADV7533 Exported Functions + * @{ + */ + +/** + * @brief Initializes the ADV7533 bridge. + * @param None + * @retval Status + */ +uint8_t ADV7533_Init(void) +{ + HDMI_IO_Init(); + + /* Configure the IC2 address for CEC_DSI interface */ + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0xE1, ADV7533_CEC_DSI_I2C_ADDR); + + return 0; +} + +/** + * @brief Power on the ADV7533 bridge. + * @param None + * @retval None + */ +void ADV7533_PowerOn(void) +{ + uint8_t tmp; + + /* Power on */ + tmp = HDMI_IO_Read(ADV7533_MAIN_I2C_ADDR, 0x41); + tmp &= ~0x40; + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0x41, tmp); +} + +/** + * @brief Power off the ADV7533 bridge. + * @param None + * @retval None + */ +void ADV7533_PowerDown(void) +{ + uint8_t tmp; + + /* Power down */ + tmp = HDMI_IO_Read(ADV7533_MAIN_I2C_ADDR, 0x41); + tmp |= 0x40; + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0x41, tmp); +} + +/** + * @brief Configure the DSI-HDMI ADV7533 bridge for video. + * @param config : pointer to adv7533ConfigTypeDef that contains the + * video configuration parameters + * @retval None + */ +void ADV7533_Configure(adv7533ConfigTypeDef * config) +{ + uint8_t tmp; + + /* Sequence from Section 3 - Quick Start Guide */ + + /* ADV7533 Power Settings */ + /* Power down */ + tmp = HDMI_IO_Read(ADV7533_MAIN_I2C_ADDR, 0x41); + tmp &= ~0x40; + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0x41, tmp); + /* HPD Override */ + tmp = HDMI_IO_Read(ADV7533_MAIN_I2C_ADDR, 0xD6); + tmp |= 0x40; + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0xD6, tmp); + /* Gate DSI LP Oscillator and DSI Bias Clock Powerdown */ + tmp = HDMI_IO_Read(ADV7533_CEC_DSI_I2C_ADDR, 0x03); + tmp &= ~0x02; + HDMI_IO_Write(ADV7533_CEC_DSI_I2C_ADDR, 0x03, tmp); + + /* Fixed registers that must be set on power-up */ + tmp = HDMI_IO_Read(ADV7533_MAIN_I2C_ADDR, 0x16); + tmp &= ~0x3E; + tmp |= 0x20; + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0x16, tmp); + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0x9A, 0xE0); + tmp = HDMI_IO_Read(ADV7533_MAIN_I2C_ADDR, 0xBA); + tmp &= ~0xF8; + tmp |= 0x70; + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0xBA, tmp); + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0xDE, 0x82); + + tmp = HDMI_IO_Read(ADV7533_MAIN_I2C_ADDR, 0xE4); + tmp |= 0x40; + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0xE4, tmp); + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0xE5, 0x80); + + tmp = HDMI_IO_Read(ADV7533_CEC_DSI_I2C_ADDR, 0x15); + tmp &= ~0x30; + tmp |= 0x10; + tmp = HDMI_IO_Read(ADV7533_CEC_DSI_I2C_ADDR, 0x17); + tmp &= ~0xF0; + tmp |= 0xD0; + HDMI_IO_Write(ADV7533_CEC_DSI_I2C_ADDR, 0x17, tmp); + tmp = HDMI_IO_Read(ADV7533_CEC_DSI_I2C_ADDR, 0x24); + tmp &= ~0x10; + HDMI_IO_Write(ADV7533_CEC_DSI_I2C_ADDR, 0x24, tmp); + tmp = HDMI_IO_Read(ADV7533_CEC_DSI_I2C_ADDR, 0x57); + tmp |= 0x01; + tmp |= 0x10; + HDMI_IO_Write(ADV7533_CEC_DSI_I2C_ADDR, 0x57, tmp); + + /* Configure the number of DSI lanes */ + HDMI_IO_Write(ADV7533_CEC_DSI_I2C_ADDR, 0x1C, (config->DSI_LANES << 4)); + + /* Setup video output mode */ + /* Select HDMI mode */ + tmp = HDMI_IO_Read(ADV7533_MAIN_I2C_ADDR, 0xAF); + tmp |= 0x02; + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0xAF, tmp); + /* HDMI Output Enable */ + tmp = HDMI_IO_Read(ADV7533_CEC_DSI_I2C_ADDR, 0x03); + tmp |= 0x80; + HDMI_IO_Write(ADV7533_CEC_DSI_I2C_ADDR, 0x03, tmp); + + /* GC packet enable */ + tmp = HDMI_IO_Read(ADV7533_MAIN_I2C_ADDR, 0x40); + tmp |= 0x80; + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0x40, tmp); + /* Input color depth 24-bit per pixel */ + tmp = HDMI_IO_Read(ADV7533_MAIN_I2C_ADDR, 0x4C); + tmp &= ~0x0F; + tmp |= 0x03; + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0x4C, tmp); + /* Down dither output color depth */ + HDMI_IO_Write(ADV7533_MAIN_I2C_ADDR, 0x49, 0xfc); + + /* Internal timing disabled */ + tmp = HDMI_IO_Read(ADV7533_CEC_DSI_I2C_ADDR, 0x27); + tmp &= ~0x80; + HDMI_IO_Write(ADV7533_CEC_DSI_I2C_ADDR, 0x27, tmp); +} + +/** + * @brief Enable video pattern generation. + * @param None + * @retval None + */ +void ADV7533_PatternEnable(void) +{ + /* Timing generator enable */ + HDMI_IO_Write(ADV7533_CEC_DSI_I2C_ADDR, 0x55, 0x80); /* Color bar */ + HDMI_IO_Write(ADV7533_CEC_DSI_I2C_ADDR, 0x55, 0xA0); /* Color ramp */ + + HDMI_IO_Write(ADV7533_CEC_DSI_I2C_ADDR, 0x03, 0x89); + HDMI_IO_Write(ADV7533_CEC_DSI_I2C_ADDR, 0xAF, 0x16); +} + +/** + * @brief Disable video pattern generation. + * @param none + * @retval none + */ +void ADV7533_PatternDisable(void) +{ + /* Timing generator enable */ + HDMI_IO_Write(ADV7533_CEC_DSI_I2C_ADDR, 0x55, 0x00); +} + +/** + * @brief Initializes the ADV7533 audio interface. + * @param DeviceAddr: Device address on communication Bus. + * @param OutputDevice: Not used (for compatiblity only). + * @param Volume: Not used (for compatiblity only). + * @param AudioFreq: Audio Frequency + * @retval 0 if correct communication, else wrong communication + */ +uint32_t adv7533_AudioInit(uint16_t DeviceAddr, uint16_t OutputDevice, uint8_t Volume,uint32_t AudioFreq) +{ + uint32_t val = 4096; + uint8_t tmp = 0; + + /* Audio data enable*/ + tmp = HDMI_IO_Read(ADV7533_CEC_DSI_I2C_ADDR, 0x05); + tmp &= ~0x20; + HDMI_IO_Write(ADV7533_CEC_DSI_I2C_ADDR, 0x05, tmp); + + /* HDMI statup */ + tmp= (uint8_t)((val & 0xF0000)>>16); + HDMI_IO_Write(DeviceAddr, 0x01, tmp); + + tmp= (uint8_t)((val & 0xFF00)>>8); + HDMI_IO_Write(DeviceAddr, 0x02, tmp); + + tmp= (uint8_t)((val & 0xFF)); + HDMI_IO_Write(DeviceAddr, 0x03, tmp); + + /* Enable spdif */ + tmp = HDMI_IO_Read(DeviceAddr, 0x0B); + tmp |= 0x80; + HDMI_IO_Write(DeviceAddr, 0x0B, tmp); + + /* Enable I2S */ + tmp = HDMI_IO_Read(DeviceAddr, 0x0C); + tmp |=0x04; + HDMI_IO_Write(DeviceAddr, 0x0C, tmp); + + /* Set audio sampling frequency */ + adv7533_SetFrequency(DeviceAddr, AudioFreq); + + /* Select SPDIF is 0x10 , I2S=0x00 */ + tmp = HDMI_IO_Read(ADV7533_MAIN_I2C_ADDR, 0x0A); + tmp &=~ 0x10; + HDMI_IO_Write(DeviceAddr, 0x0A, tmp); + + /* Set v1P2 enable */ + tmp = HDMI_IO_Read(DeviceAddr, 0xE4); + tmp |= 0x80; + HDMI_IO_Write(DeviceAddr, 0xE4, tmp); + + return 0; +} + +/** + * @brief Deinitializes the adv7533 + * @param None + * @retval None + */ +void adv7533_DeInit(void) +{ + /* Deinitialize Audio adv7533 interface */ + AUDIO_IO_DeInit(); +} + +/** + * @brief Get the adv7533 ID. + * @param DeviceAddr: Device address on communication Bus. + * @retval The adv7533 ID + */ +uint32_t adv7533_ReadID(uint16_t DeviceAddr) +{ + uint32_t tmp = 0; + + tmp = HDMI_IO_Read(DeviceAddr, ADV7533_CHIPID_ADDR0); + tmp = (tmp<<8); + tmp |= HDMI_IO_Read(DeviceAddr, ADV7533_CHIPID_ADDR1); + + return(tmp); +} + +/** + * @brief Pauses playing on the audio hdmi + * @param DeviceAddr: Device address on communication Bus. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t adv7533_Pause(uint16_t DeviceAddr) +{ + return(adv7533_SetMute(DeviceAddr,AUDIO_MUTE_ON)); +} + +/** + * @brief Resumes playing on the audio hdmi. + * @param DeviceAddr: Device address on communication Bus. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t adv7533_Resume(uint16_t DeviceAddr) +{ + return(adv7533_SetMute(DeviceAddr,AUDIO_MUTE_OFF)); +} + +/** + * @brief Start the audio hdmi play feature. + * @note For this codec no Play options are required. + * @param DeviceAddr: Device address on communication Bus. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t adv7533_Play(uint16_t DeviceAddr ,uint16_t* pBuffer ,uint16_t Size) +{ + return(adv7533_SetMute(DeviceAddr,AUDIO_MUTE_OFF)); +} + +/** + * @brief Stop playing on the audio hdmi + * @param DeviceAddr: Device address on communication Bus. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t adv7533_Stop(uint16_t DeviceAddr,uint32_t cmd) +{ + return(adv7533_SetMute(DeviceAddr,AUDIO_MUTE_ON)); +} + +/** + * @brief Enables or disables the mute feature on the audio hdmi. + * @param DeviceAddr: Device address on communication Bus. + * @param Cmd: AUDIO_MUTE_ON to enable the mute or AUDIO_MUTE_OFF to disable the + * mute mode. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t adv7533_SetMute(uint16_t DeviceAddr, uint32_t Cmd) +{ + uint8_t tmp = 0; + + tmp = HDMI_IO_Read(DeviceAddr, 0x0D); + if (Cmd == AUDIO_MUTE_ON) + { + /* enable audio mute*/ + tmp |= 0x40; + HDMI_IO_Write(DeviceAddr, 0x0D, tmp); + } + else + { + /*audio mute off disable the mute */ + tmp &= ~0x40; + HDMI_IO_Write(DeviceAddr, 0x0D, tmp); + } + return 0; +} + +/** + * @brief Sets output mode. + * @param DeviceAddr: Device address on communication Bus. + * @param Output : hdmi output. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t adv7533_SetOutputMode(uint16_t DeviceAddr, uint8_t Output) +{ + return 0; +} + +/** + * @brief Sets volumee. + * @param DeviceAddr: Device address on communication Bus. + * @param Volume : volume value. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t adv7533_SetVolume(uint16_t DeviceAddr, uint8_t Volume) +{ + return 0; +} + +/** + * @brief Resets adv7533 registers. + * @param DeviceAddr: Device address on communication Bus. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t adv7533_Reset(uint16_t DeviceAddr) +{ + return 0; +} + +/** + * @brief Sets new frequency. + * @param DeviceAddr: Device address on communication Bus. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t adv7533_SetFrequency(uint16_t DeviceAddr, uint32_t AudioFreq) +{ + uint8_t tmp = 0; + + tmp = HDMI_IO_Read(DeviceAddr, 0x15); + tmp &= (~0xF0); + /* Clock Configurations */ + switch (AudioFreq) + { + case AUDIO_FREQUENCY_32K: + /* Sampling Frequency =32 KHZ*/ + tmp |= 0x30; + HDMI_IO_Write(DeviceAddr, 0x15, tmp); + break; + case AUDIO_FREQUENCY_44K: + /* Sampling Frequency =44,1 KHZ*/ + tmp |= 0x00; + HDMI_IO_Write(DeviceAddr, 0x15, tmp); + break; + + case AUDIO_FREQUENCY_48K: + /* Sampling Frequency =48KHZ*/ + tmp |= 0x20; + HDMI_IO_Write(DeviceAddr, 0x15, tmp); + break; + + case AUDIO_FREQUENCY_96K: + /* Sampling Frequency =96 KHZ*/ + tmp |= 0xA0; + HDMI_IO_Write(DeviceAddr, 0x15, tmp); + break; + + case AUDIO_FREQUENCY_88K: + /* Sampling Frequency =88,2 KHZ*/ + tmp |= 0x80; + HDMI_IO_Write(DeviceAddr, 0x15, tmp); + break; + + case AUDIO_FREQUENCY_176K: + /* Sampling Frequency =176,4 KHZ*/ + tmp |= 0xC0; + HDMI_IO_Write(DeviceAddr, 0x15, tmp); + break; + + case AUDIO_FREQUENCY_192K: + /* Sampling Frequency =192KHZ*/ + tmp |= 0xE0; + HDMI_IO_Write(DeviceAddr, 0x15, tmp); + break; + } + return 0; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/adv7533/adv7533.h b/src/port_stm32f7/common/bsp_drivers/Components/adv7533/adv7533.h new file mode 100644 index 00000000..85b42ff0 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/adv7533/adv7533.h @@ -0,0 +1,230 @@ + +/** + ****************************************************************************** + * @file adv7533.h + * @author MCD Application Team + * @brief This file contains all the constants parameters for the ADV7533 + * which is the HDMI bridge between DSI and HDMI + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __ADV7533_H +#define __ADV7533_H + +/* Includes ------------------------------------------------------------------*/ +#include "../Common/audio.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup adv7533 + * @{ + */ + +/** @addtogroup ADV7533_Exported_Types + * @{ + */ + +typedef struct { + uint8_t DSI_LANES; + uint16_t HACT; + uint16_t HSYNC; + uint16_t HBP; + uint16_t HFP; + uint16_t VACT; + uint16_t VSYNC; + uint16_t VBP; + uint16_t VFP; + uint8_t ASPECT_RATIO; +} adv7533ConfigTypeDef; + +/** @defgroup ADV7533_Exported_Constants + * @{ + */ + +/** + * @brief HDMI audio output DEVICE + */ +#define OUTPUT_DEVICE_ADV7533_HDMI ((uint16_t)0x1000) + +/** + * @brief ADV7533 I2C Addresses 0x7A / 0x78 + */ +#define ADV7533_MAIN_I2C_ADDR ((uint8_t)0x7A) +#define ADV7533_CEC_DSI_I2C_ADDR ((uint8_t)0x78) + +/** + * @brief ADV7533 Aspect ratio + */ +#define ADV7533_ASPECT_RATIO_16_9 ((uint8_t)0x00) +#define ADV7533_ASPECT_RATIO_4_3 ((uint8_t)0x01) + +/** + * @brief ADV7533 Aspect ratio + */ +#define ADV7533_MODE_HDMI 0x0 +#define ADV7533_MODE_DVI 0x1 + +/** + * @brief ADV7533 Main Registers + */ +#define ADV7533_MAIN_SYNC_REG ((uint8_t)0x17) +#define ADV7533_MAIN_POWER_DOWN_REG ((uint8_t)0x41) +#define ADV7533_MAIN_HPG_REG ((uint8_t)0x42) + +/** + * @brief ADV7533 Main Features Parameters + */ + +/** + * @brief ADV7533 CEC DSI Registers + */ +#define ADV7533_CEC_DSI_INTERNAL_TIMING_REG ((uint8_t)0x27) +#define ADV7533_CEC_DSI_TOTAL_WIDTH_H_REG ((uint8_t)0x28) +#define ADV7533_CEC_DSI_TOTAL_WIDTH_L_REG ((uint8_t)0x29) +#define ADV7533_CEC_DSI_HSYNC_H_REG ((uint8_t)0x2A) +#define ADV7533_CEC_DSI_HSYNC_L_REG ((uint8_t)0x2B) +#define ADV7533_CEC_DSI_HFP_H_REG ((uint8_t)0x2C) +#define ADV7533_CEC_DSI_HFP_L_REG ((uint8_t)0x2D) +#define ADV7533_CEC_DSI_HBP_H_REG ((uint8_t)0x2E) +#define ADV7533_CEC_DSI_HBP_L_REG ((uint8_t)0x2F) + +#define ADV7533_CEC_DSI_TOTAL_HEIGHT_H_REG ((uint8_t)0x30) +#define ADV7533_CEC_DSI_TOTAL_HEIGHT_L_REG ((uint8_t)0x31) +#define ADV7533_CEC_DSI_VSYNC_H_REG ((uint8_t)0x32) +#define ADV7533_CEC_DSI_VSYNC_L_REG ((uint8_t)0x33) +#define ADV7533_CEC_DSI_VFP_H_REG ((uint8_t)0x34) +#define ADV7533_CEC_DSI_VFP_L_REG ((uint8_t)0x35) +#define ADV7533_CEC_DSI_VBP_H_REG ((uint8_t)0x36) +#define ADV7533_CEC_DSI_VBP_L_REG ((uint8_t)0x37) + +/** @Brief adv7533 ID + */ +#define ADV7533_ID 0x7533 + +/** @Brief device ID register + */ +#define ADV7533_CHIPID_ADDR0 0x00 +#define ADV7533_CHIPID_ADDR1 0x01 + +/* MUTE commands */ +#define AUDIO_MUTE_ON 1 +#define AUDIO_MUTE_OFF 0 + +/* AUDIO FREQUENCY */ +#define AUDIO_FREQUENCY_192K ((uint32_t)192000) +#define AUDIO_FREQUENCY_176K ((uint32_t)176400) +#define AUDIO_FREQUENCY_96K ((uint32_t)96000) +#define AUDIO_FREQUENCY_88K ((uint32_t)88200) +#define AUDIO_FREQUENCY_48K ((uint32_t)48000) +#define AUDIO_FREQUENCY_44K ((uint32_t)44100) +#define AUDIO_FREQUENCY_32K ((uint32_t)32000) + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ + +/** @defgroup ADV7533_Exported_Macros ADV7533 Exported Macros + * @{ + */ + +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ + +/** @addtogroup ADV7533_Exported_Functions + * @{ + */ + +/*------------------------------------------------------------------------------ + HDMI video functions +------------------------------------------------------------------------------*/ +uint8_t ADV7533_Init(void); +void ADV7533_PowerOn(void); +void ADV7533_PowerDown(void); +void ADV7533_Configure(adv7533ConfigTypeDef * config); +void ADV7533_PatternEnable(void); +void ADV7533_PatternDisable(void); + +/*------------------------------------------------------------------------------ + HDMI Audio functions +------------------------------------------------------------------------------*/ +uint32_t adv7533_AudioInit(uint16_t DeviceAddr, uint16_t OutputDevice, uint8_t Volume,uint32_t AudioFreq); +void adv7533_DeInit(void); +uint32_t adv7533_ReadID(uint16_t DeviceAddr); +uint32_t adv7533_Play(uint16_t DeviceAddr, uint16_t* pBuffer, uint16_t Size); +uint32_t adv7533_Stop(uint16_t DeviceAddr,uint32_t Cmd); +uint32_t adv7533_Pause(uint16_t DeviceAddr); +uint32_t adv7533_Resume(uint16_t DeviceAddr); +uint32_t adv7533_SetMute(uint16_t DeviceAddr, uint32_t Cmd); +uint32_t adv7533_SetVolume(uint16_t, uint8_t); +uint32_t adv7533_Reset(uint16_t DeviceAddr); +uint32_t adv7533_SetOutputMode(uint16_t DeviceAddr, uint8_t Output); +uint32_t adv7533_SetFrequency(uint16_t DeviceAddr, uint32_t AudioFreq); + + +/* HDMI IO functions */ +void HDMI_IO_Init(void); +void HDMI_IO_Write(uint8_t addr, uint8_t reg, uint8_t value); +uint8_t HDMI_IO_Read(uint8_t addr, uint8_t reg); +void HDMI_IO_Delay(uint32_t delay); +void AUDIO_IO_DeInit(void); + +/** + * @} + */ + +/* HDMI Audio driver structure */ +extern AUDIO_DrvTypeDef adv7533_drv; + +#endif /* __ADV7533_H */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ampire480272/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/ampire480272/Release_Notes.html new file mode 100644 index 00000000..b675e6c9 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ampire480272/Release_Notes.html @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + Release Notes for Ampire480272 LCD Component Driver + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for Ampire480272 LCD Component Driver

+

Copyright +2014 STMicroelectronics

+

+
+

 

+ + + + + + +
+ + +

Update History

V1.0.1 / 07-April-2017

Main Changes

  • Update comments to be used for PDSC generation

V1.0.0 / 18-February-2014

+ + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • + + First official release of ampire480272 LCD component  
  • +

License

+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ampire480272/ampire480272.h b/src/port_stm32f7/common/bsp_drivers/Components/ampire480272/ampire480272.h new file mode 100644 index 00000000..bf1d9ec6 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ampire480272/ampire480272.h @@ -0,0 +1,119 @@ +/** + ****************************************************************************** + * @file ampire480272.h + * @author MCD Application Team + * @brief This file contains all the constants parameters for the ampire480272 + * LCD component. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __AMPIRE480272_H +#define __AMPIRE480272_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup ampire480272 + * @{ + */ + +/** @defgroup AMPIRE480272_Exported_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup AMPIRE480272_Exported_Constants + * @{ + */ + +/** + * @brief AMPIRE480272 Size + */ +#define AMPIRE480272_WIDTH ((uint16_t)480) /* LCD PIXEL WIDTH */ +#define AMPIRE480272_HEIGHT ((uint16_t)272) /* LCD PIXEL HEIGHT */ + +/** + * @brief AMPIRE480272 Timing + */ +#define AMPIRE480272_HSYNC ((uint16_t)41) /* Horizontal synchronization */ +#define AMPIRE480272_HBP ((uint16_t)2) /* Horizontal back porch */ +#define AMPIRE480272_HFP ((uint16_t)2) /* Horizontal front porch */ +#define AMPIRE480272_VSYNC ((uint16_t)10) /* Vertical synchronization */ +#define AMPIRE480272_VBP ((uint16_t)2) /* Vertical back porch */ +#define AMPIRE480272_VFP ((uint16_t)2) /* Vertical front porch */ + +/** + * @brief AMPIRE480272 frequency divider + */ +#define AMPIRE480272_FREQUENCY_DIVIDER 5 /* LCD Frequency divider */ +/** + * @} + */ + +/** @defgroup AMPIRE480272_Exported_Functions + * @{ + */ + +/** + * @} + */ +#ifdef __cplusplus +} +#endif + +#endif /* __AMPIRE480272_H */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ampire640480/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/ampire640480/Release_Notes.html new file mode 100644 index 00000000..203e0261 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ampire640480/Release_Notes.html @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + Release Notes for Ampire480272 LCD Component Driver + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for Ampire640480 LCD Component Driver

+

Copyright +2014 STMicroelectronics

+

+
+

 

+ + + + + + +
+ + +

Update History

V1.0.1 / 07-April-2017

Main Changes

  • Update comments to be used for PDSC generation

V1.0.0 / 18-February-2014

+ + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + + First official release of ampire640480 LCD component 
  • +

License

+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ampire640480/ampire640480.h b/src/port_stm32f7/common/bsp_drivers/Components/ampire640480/ampire640480.h new file mode 100644 index 00000000..0f566fc6 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ampire640480/ampire640480.h @@ -0,0 +1,119 @@ +/** + ****************************************************************************** + * @file ampire640480.h + * @author MCD Application Team + * @brief This file contains all the constants parameters for the ampire640480 + * LCD component. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __AMPIRE640480_H +#define __AMPIRE640480_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup ampire640480 + * @{ + */ + +/** @defgroup AMPIRE640480_Exported_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup AMPIRE640480_Exported_Constants + * @{ + */ + +/** + * @brief AMPIRE640480 Size + */ +#define AMPIRE640480_WIDTH ((uint16_t)640) /* LCD PIXEL WIDTH */ +#define AMPIRE640480_HEIGHT ((uint16_t)480) /* LCD PIXEL HEIGHT */ + +/** + * @brief AMPIRE640480 Timing + */ +#define AMPIRE640480_HSYNC ((uint16_t)30) /* Horizontal synchronization */ +#define AMPIRE640480_HBP ((uint16_t)114) /* Horizontal back porch */ +#define AMPIRE640480_HFP ((uint16_t)16) /* Horizontal front porch */ +#define AMPIRE640480_VSYNC ((uint16_t)3) /* Vertical synchronization */ +#define AMPIRE640480_VBP ((uint16_t)32) /* Vertical back porch */ +#define AMPIRE640480_VFP ((uint16_t)10) /* Vertical front porch */ + +/** + * @brief AMPIRE640480 frequency divider + */ +#define AMPIRE640480_FREQUENCY_DIVIDER 3 /* LCD Frequency divider */ +/** + * @} + */ + +/** @defgroup AMPIRE640480_Exported_Functions + * @{ + */ + +/** + * @} + */ +#ifdef __cplusplus +} +#endif + +#endif /* __AMPIRE640480_H */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/exc7200/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/exc7200/Release_Notes.html new file mode 100644 index 00000000..aa64c3fa --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/exc7200/Release_Notes.html @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + Release Notes for STM32 BSP EXC7200 Components Drivers + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for EXC7200 Component Driver

+

Copyright +2015 STMicroelectronics

+

+
+

 

+ + + + + + +

Update History

V1.0.2 / 07-April-2017

Main Changes

  • Update comments to be used for PDSC generation

V1.0.1 +/ 21-September-2015

+Main +Changes
  • exc7200.c:
    • Update the I2C slave read address within exc7200_TS_DetectTouch() function.
    • Update exc7200_TS_GetXY() function to return correct Touch Screen positions.

V1.0.0 +/ 28-April-2015

+

Main +Changes

+ + + + + + + + + +
  • First official +release of  EXC7200 TS component driver

License

+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+
For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32
+

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/exc7200/exc7200.c b/src/port_stm32f7/common/bsp_drivers/Components/exc7200/exc7200.c new file mode 100644 index 00000000..9e2dbb93 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/exc7200/exc7200.c @@ -0,0 +1,240 @@ +/** + ****************************************************************************** + * @file exc7200.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the EXC7200 + * Touch-screen controller. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "exc7200.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Component + * @{ + */ + +/** @defgroup EXC7200 + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ + +/** @defgroup EXC7200_Private_Types_Definitions + * @{ + */ + +/* Private define ------------------------------------------------------------*/ + +/** @defgroup EXC7200_Private_Defines + * @{ + */ + +/* Private macro -------------------------------------------------------------*/ + +/** @defgroup EXC7200_Private_Macros + * @{ + */ + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup EXC7200_Private_Variables + * @{ + */ + +/* Touch screen driver structure initialization */ +TS_DrvTypeDef exc7200_ts_drv = +{ + exc7200_Init, + exc7200_ReadID, + exc7200_Reset, + + exc7200_TS_Start, + exc7200_TS_DetectTouch, + exc7200_TS_GetXY, + + exc7200_TS_EnableIT, + exc7200_TS_ClearIT, + exc7200_TS_ITStatus, + exc7200_TS_DisableIT, +}; + +uint8_t aBufferTS[10]; + +/** + * @} + */ + +/* Private function prototypes -----------------------------------------------*/ + +/** @defgroup exc7200_Private_Function_Prototypes + * @{ + */ + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup exc7200_Private_Functions + * @{ + */ + +/** + * @brief Initialize the exc7200 and configure the needed hardware resources + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void exc7200_Init(uint16_t DeviceAddr) +{ + /* Initialize IO BUS layer */ + IOE_Init(); + +} + +/** + * @brief Reset the exc7200 by Software. + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void exc7200_Reset(uint16_t DeviceAddr) +{ + +} + +/** + * @brief Read the exc7200 IO Expander device ID. + * @param DeviceAddr: Device address on communication Bus. + * @retval The Device ID (two bytes). + */ +uint16_t exc7200_ReadID(uint16_t DeviceAddr) +{ + return 0; +} + +/** + * @brief Configures the touch Screen Controller (Single point detection) + * @param DeviceAddr: Device address on communication Bus. + * @retval None. + */ +void exc7200_TS_Start(uint16_t DeviceAddr) +{ +} + +/** + * @brief Return if there is touch detected or not. + * @param DeviceAddr: Device address on communication Bus. + * @retval Touch detected state. + */ +uint8_t exc7200_TS_DetectTouch(uint16_t DeviceAddr) +{ + /* Read TS data : Send I2C Slave address + 1 Bit0=1 for:read */ + IOE_ReadMultiple(DeviceAddr | 1, EXC7200_READ_CMD, aBufferTS, 10); + + /* check for first byte */ + if (aBufferTS[1]==0x83) + { + return 1; + } + + return 0; +} + +/** + * @brief Get the touch screen X and Y positions values + * @param DeviceAddr: Device address on communication Bus. + * @param X: Pointer to X position value + * @param Y: Pointer to Y position value + * @retval None. + */ +void exc7200_TS_GetXY(uint16_t DeviceAddr, uint16_t *X, uint16_t *Y) +{ + /* Calculate positions */ + *X = (((aBufferTS[3]&0x00ff) << 4) | ((aBufferTS[2]&0x00f0) >> 4)) << 1; + *Y = (((aBufferTS[5]&0x00ff) << 4) | ((aBufferTS[4]&0x00f0) >> 4)) << 1; + + /* Dummy Read to deactivate read mode */ + IOE_ReadMultiple(DeviceAddr, EXC7200_READ_CMD, aBufferTS, 10); +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void exc7200_TS_EnableIT(uint16_t DeviceAddr) +{ +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void exc7200_TS_DisableIT(uint16_t DeviceAddr) +{ +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval TS interrupts status + */ +uint8_t exc7200_TS_ITStatus(uint16_t DeviceAddr) +{ + return 0; +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void exc7200_TS_ClearIT(uint16_t DeviceAddr) +{ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/exc7200/exc7200.h b/src/port_stm32f7/common/bsp_drivers/Components/exc7200/exc7200.h new file mode 100644 index 00000000..a03b89fa --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/exc7200/exc7200.h @@ -0,0 +1,135 @@ +/** + ****************************************************************************** + * @file exc7200.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for the + * exc7200.c IO expander driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __EXC7200_H +#define __EXC7200_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "../Common/ts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Component + * @{ + */ + +/** @defgroup EXC7200 + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** @defgroup EXC7200_Exported_Types + * @{ + */ + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup EXC7200_Exported_Constants + * @{ + */ + +/* */ +#define EXC7200_READ_CMD 0x09 + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ + +/** @defgroup exc7200_Exported_Macros + * @{ + */ + +/* Exported functions --------------------------------------------------------*/ + +/** @defgroup exc7200_Exported_Functions + * @{ + */ + +/** + * @brief exc7200 Control functions + */ +void exc7200_Init(uint16_t DeviceAddr); +void exc7200_Reset(uint16_t DeviceAddr); +uint16_t exc7200_ReadID(uint16_t DeviceAddr); +void exc7200_TS_Start(uint16_t DeviceAddr); +uint8_t exc7200_TS_DetectTouch(uint16_t DeviceAddr); +void exc7200_TS_GetXY(uint16_t DeviceAddr, uint16_t *X, uint16_t *Y); +void exc7200_TS_EnableIT(uint16_t DeviceAddr); +void exc7200_TS_DisableIT(uint16_t DeviceAddr); +uint8_t exc7200_TS_ITStatus (uint16_t DeviceAddr); +void exc7200_TS_ClearIT (uint16_t DeviceAddr); + +void IOE_Init(void); +void IOE_Delay(uint32_t delay); +uint8_t IOE_Read(uint8_t addr, uint8_t reg); +uint16_t IOE_ReadMultiple(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t length); +void IOE_WriteMultiple(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t length); + +/* Touch screen driver structure */ +extern TS_DrvTypeDef exc7200_ts_drv; + +#ifdef __cplusplus +} +#endif +#endif /* __EXC7200_H */ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ft5336/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/ft5336/Release_Notes.html new file mode 100644 index 00000000..46e33a51 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ft5336/Release_Notes.html @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + Release Notes for FT5336GQQ Component Driver + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for FT5336GQQ Component Driver

+

Copyright +2015 STMicroelectronics

+

+
+

 

+ + + + + + +
+ + +

Update History

V1.0.1 / 07-April-2017

Main Changes

  • Update comments to be used for PDSC generation

V1.0.0 / 25-June-2015

+ + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • First official release of FT5336 TS driver
  • +

License

+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ft5336/ft5336.c b/src/port_stm32f7/common/bsp_drivers/Components/ft5336/ft5336.c new file mode 100644 index 00000000..1cd70343 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ft5336/ft5336.c @@ -0,0 +1,623 @@ +/** + ****************************************************************************** + * @file ft5336.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the FT5336 + * touch screen devices. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "ft5336.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Component + * @{ + */ + +/** @defgroup FT5336 + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ + +/** @defgroup FT5336_Private_Types_Definitions + * @{ + */ + +/* Private define ------------------------------------------------------------*/ + +/** @defgroup FT5336_Private_Defines + * @{ + */ + +/* Private macro -------------------------------------------------------------*/ + +/** @defgroup FT5336_Private_Macros + * @{ + */ + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup FT5336_Private_Variables + * @{ + */ + +/* Touch screen driver structure initialization */ +TS_DrvTypeDef ft5336_ts_drv = +{ + ft5336_Init, + ft5336_ReadID, + ft5336_Reset, + + ft5336_TS_Start, + ft5336_TS_DetectTouch, + ft5336_TS_GetXY, + + ft5336_TS_EnableIT, + ft5336_TS_ClearIT, + ft5336_TS_ITStatus, + ft5336_TS_DisableIT + +}; + +/* Global ft5336 handle */ +static ft5336_handle_TypeDef ft5336_handle = { FT5336_I2C_NOT_INITIALIZED, 0, 0}; + +/** + * @} + */ + +/** @defgroup ft5336_Private_Function_Prototypes + * @{ + */ + +/* Private functions prototypes-----------------------------------------------*/ + +/** + * @brief Return the status of I2C was initialized or not. + * @param None. + * @retval : I2C initialization status. + */ +static uint8_t ft5336_Get_I2C_InitializedStatus(void); + +/** + * @brief I2C initialize if needed. + * @param None. + * @retval : None. + */ +static void ft5336_I2C_InitializeIfRequired(void); + +/** + * @brief Basic static configuration of TouchScreen + * @param DeviceAddr: FT5336 Device address for communication on I2C Bus. + * @retval Status FT5336_STATUS_OK or FT5336_STATUS_NOT_OK. + */ +static uint32_t ft5336_TS_Configure(uint16_t DeviceAddr); + +/** @defgroup ft5336_Private_Functions + * @{ + */ + +/** @defgroup ft5336_Public_Function_Body + * @{ + */ + +/* Public functions bodies-----------------------------------------------*/ + + +/** + * @brief Initialize the ft5336 communication bus + * from MCU to FT5336 : ie I2C channel initialization (if required). + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT5336). + * @retval None + */ +void ft5336_Init(uint16_t DeviceAddr) +{ + /* Wait at least 200ms after power up before accessing registers + * Trsi timing (Time of starting to report point after resetting) from FT5336GQQ datasheet */ + TS_IO_Delay(200); + + /* Initialize I2C link if needed */ + ft5336_I2C_InitializeIfRequired(); +} + +/** + * @brief Software Reset the ft5336. + * @note : Not applicable to FT5336. + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT5336). + * @retval None + */ +void ft5336_Reset(uint16_t DeviceAddr) +{ + /* Do nothing */ + /* No software reset sequence available in FT5336 IC */ +} + +/** + * @brief Read the ft5336 device ID, pre initialize I2C in case of need to be + * able to read the FT5336 device ID, and verify this is a FT5336. + * @param DeviceAddr: I2C FT5336 Slave address. + * @retval The Device ID (two bytes). + */ +uint16_t ft5336_ReadID(uint16_t DeviceAddr) +{ + volatile uint8_t ucReadId = 0; + uint8_t nbReadAttempts = 0; + uint8_t bFoundDevice = 0; /* Device not found by default */ + + /* Initialize I2C link if needed */ + ft5336_I2C_InitializeIfRequired(); + + /* At maximum 4 attempts to read ID : exit at first finding of the searched device ID */ + for(nbReadAttempts = 0; ((nbReadAttempts < 3) && !(bFoundDevice)); nbReadAttempts++) + { + /* Read register FT5336_CHIP_ID_REG as DeviceID detection */ + ucReadId = TS_IO_Read(DeviceAddr, FT5336_CHIP_ID_REG); + + /* Found the searched device ID ? */ + if(ucReadId == FT5336_ID_VALUE) + { + /* Set device as found */ + bFoundDevice = 1; + } + } + + /* Return the device ID value */ + return (ucReadId); +} + +/** + * @brief Configures the touch Screen IC device to start detecting touches + * @param DeviceAddr: Device address on communication Bus (I2C slave address). + * @retval None. + */ +void ft5336_TS_Start(uint16_t DeviceAddr) +{ + /* Minimum static configuration of FT5336 */ + FT5336_ASSERT(ft5336_TS_Configure(DeviceAddr)); + + /* By default set FT5336 IC in Polling mode : no INT generation on FT5336 for new touch available */ + /* Note TS_INT is active low */ + ft5336_TS_DisableIT(DeviceAddr); +} + +/** + * @brief Return if there is touches detected or not. + * Try to detect new touches and forget the old ones (reset internal global + * variables). + * @param DeviceAddr: Device address on communication Bus. + * @retval : Number of active touches detected (can be 0, 1 or 2). + */ +uint8_t ft5336_TS_DetectTouch(uint16_t DeviceAddr) +{ + volatile uint8_t nbTouch = 0; + + /* Read register FT5336_TD_STAT_REG to check number of touches detection */ + nbTouch = TS_IO_Read(DeviceAddr, FT5336_TD_STAT_REG); + nbTouch &= FT5336_TD_STAT_MASK; + + if(nbTouch > FT5336_MAX_DETECTABLE_TOUCH) + { + /* If invalid number of touch detected, set it to zero */ + nbTouch = 0; + } + + /* Update ft5336 driver internal global : current number of active touches */ + ft5336_handle.currActiveTouchNb = nbTouch; + + /* Reset current active touch index on which to work on */ + ft5336_handle.currActiveTouchIdx = 0; + + return(nbTouch); +} + +/** + * @brief Get the touch screen X and Y positions values + * Manage multi touch thanks to touch Index global + * variable 'ft5336_handle.currActiveTouchIdx'. + * @param DeviceAddr: Device address on communication Bus. + * @param X: Pointer to X position value + * @param Y: Pointer to Y position value + * @retval None. + */ +void ft5336_TS_GetXY(uint16_t DeviceAddr, uint16_t *X, uint16_t *Y) +{ + volatile uint8_t ucReadData = 0; + static uint16_t coord; + uint8_t regAddressXLow = 0; + uint8_t regAddressXHigh = 0; + uint8_t regAddressYLow = 0; + uint8_t regAddressYHigh = 0; + + if(ft5336_handle.currActiveTouchIdx < ft5336_handle.currActiveTouchNb) + { + switch(ft5336_handle.currActiveTouchIdx) + { + case 0 : + regAddressXLow = FT5336_P1_XL_REG; + regAddressXHigh = FT5336_P1_XH_REG; + regAddressYLow = FT5336_P1_YL_REG; + regAddressYHigh = FT5336_P1_YH_REG; + break; + + case 1 : + regAddressXLow = FT5336_P2_XL_REG; + regAddressXHigh = FT5336_P2_XH_REG; + regAddressYLow = FT5336_P2_YL_REG; + regAddressYHigh = FT5336_P2_YH_REG; + break; + + case 2 : + regAddressXLow = FT5336_P3_XL_REG; + regAddressXHigh = FT5336_P3_XH_REG; + regAddressYLow = FT5336_P3_YL_REG; + regAddressYHigh = FT5336_P3_YH_REG; + break; + + case 3 : + regAddressXLow = FT5336_P4_XL_REG; + regAddressXHigh = FT5336_P4_XH_REG; + regAddressYLow = FT5336_P4_YL_REG; + regAddressYHigh = FT5336_P4_YH_REG; + break; + + case 4 : + regAddressXLow = FT5336_P5_XL_REG; + regAddressXHigh = FT5336_P5_XH_REG; + regAddressYLow = FT5336_P5_YL_REG; + regAddressYHigh = FT5336_P5_YH_REG; + break; + + case 5 : + regAddressXLow = FT5336_P6_XL_REG; + regAddressXHigh = FT5336_P6_XH_REG; + regAddressYLow = FT5336_P6_YL_REG; + regAddressYHigh = FT5336_P6_YH_REG; + break; + + case 6 : + regAddressXLow = FT5336_P7_XL_REG; + regAddressXHigh = FT5336_P7_XH_REG; + regAddressYLow = FT5336_P7_YL_REG; + regAddressYHigh = FT5336_P7_YH_REG; + break; + + case 7 : + regAddressXLow = FT5336_P8_XL_REG; + regAddressXHigh = FT5336_P8_XH_REG; + regAddressYLow = FT5336_P8_YL_REG; + regAddressYHigh = FT5336_P8_YH_REG; + break; + + case 8 : + regAddressXLow = FT5336_P9_XL_REG; + regAddressXHigh = FT5336_P9_XH_REG; + regAddressYLow = FT5336_P9_YL_REG; + regAddressYHigh = FT5336_P9_YH_REG; + break; + + case 9 : + regAddressXLow = FT5336_P10_XL_REG; + regAddressXHigh = FT5336_P10_XH_REG; + regAddressYLow = FT5336_P10_YL_REG; + regAddressYHigh = FT5336_P10_YH_REG; + break; + + default : + break; + + } /* end switch(ft5336_handle.currActiveTouchIdx) */ + + /* Read low part of X position */ + ucReadData = TS_IO_Read(DeviceAddr, regAddressXLow); + coord = (ucReadData & FT5336_TOUCH_POS_LSB_MASK) >> FT5336_TOUCH_POS_LSB_SHIFT; + + /* Read high part of X position */ + ucReadData = TS_IO_Read(DeviceAddr, regAddressXHigh); + coord |= ((ucReadData & FT5336_TOUCH_POS_MSB_MASK) >> FT5336_TOUCH_POS_MSB_SHIFT) << 8; + + /* Send back ready X position to caller */ + *X = coord; + + /* Read low part of Y position */ + ucReadData = TS_IO_Read(DeviceAddr, regAddressYLow); + coord = (ucReadData & FT5336_TOUCH_POS_LSB_MASK) >> FT5336_TOUCH_POS_LSB_SHIFT; + + /* Read high part of Y position */ + ucReadData = TS_IO_Read(DeviceAddr, regAddressYHigh); + coord |= ((ucReadData & FT5336_TOUCH_POS_MSB_MASK) >> FT5336_TOUCH_POS_MSB_SHIFT) << 8; + + /* Send back ready Y position to caller */ + *Y = coord; + + ft5336_handle.currActiveTouchIdx++; /* next call will work on next touch */ + + } /* of if(ft5336_handle.currActiveTouchIdx < ft5336_handle.currActiveTouchNb) */ +} + +/** + * @brief Configure the FT5336 device to generate IT on given INT pin + * connected to MCU as EXTI. + * @param DeviceAddr: Device address on communication Bus (Slave I2C address of FT5336). + * @retval None + */ +void ft5336_TS_EnableIT(uint16_t DeviceAddr) +{ + uint8_t regValue = 0; + regValue = (FT5336_G_MODE_INTERRUPT_TRIGGER & (FT5336_G_MODE_INTERRUPT_MASK >> FT5336_G_MODE_INTERRUPT_SHIFT)) << FT5336_G_MODE_INTERRUPT_SHIFT; + + /* Set interrupt trigger mode in FT5336_GMODE_REG */ + TS_IO_Write(DeviceAddr, FT5336_GMODE_REG, regValue); +} + +/** + * @brief Configure the FT5336 device to stop generating IT on the given INT pin + * connected to MCU as EXTI. + * @param DeviceAddr: Device address on communication Bus (Slave I2C address of FT5336). + * @retval None + */ +void ft5336_TS_DisableIT(uint16_t DeviceAddr) +{ + uint8_t regValue = 0; + regValue = (FT5336_G_MODE_INTERRUPT_POLLING & (FT5336_G_MODE_INTERRUPT_MASK >> FT5336_G_MODE_INTERRUPT_SHIFT)) << FT5336_G_MODE_INTERRUPT_SHIFT; + + /* Set interrupt polling mode in FT5336_GMODE_REG */ + TS_IO_Write(DeviceAddr, FT5336_GMODE_REG, regValue); +} + +/** + * @brief Get IT status from FT5336 interrupt status registers + * Should be called Following an EXTI coming to the MCU to know the detailed + * reason of the interrupt. + * @note : This feature is not applicable to FT5336. + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT5336). + * @retval TS interrupts status : always return 0 here + */ +uint8_t ft5336_TS_ITStatus(uint16_t DeviceAddr) +{ + /* Always return 0 as feature not applicable to FT5336 */ + return 0; +} + +/** + * @brief Clear IT status in FT5336 interrupt status clear registers + * Should be called Following an EXTI coming to the MCU. + * @note : This feature is not applicable to FT5336. + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT5336). + * @retval None + */ +void ft5336_TS_ClearIT(uint16_t DeviceAddr) +{ + /* Nothing to be done here for FT5336 */ +} + +/**** NEW FEATURES enabled when Multi-touch support is enabled ****/ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + +/** + * @brief Get the last touch gesture identification (zoom, move up/down...). + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT5336). + * @param pGestureId : Pointer to get last touch gesture Identification. + * @retval None. + */ +void ft5336_TS_GetGestureID(uint16_t DeviceAddr, uint32_t * pGestureId) +{ + volatile uint8_t ucReadData = 0; + + ucReadData = TS_IO_Read(DeviceAddr, FT5336_GEST_ID_REG); + + * pGestureId = ucReadData; +} + +/** + * @brief Get the touch detailed informations on touch number 'touchIdx' (0..1) + * This touch detailed information contains : + * - weight that was applied to this touch + * - sub-area of the touch in the touch panel + * - event of linked to the touch (press down, lift up, ...) + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT5336). + * @param touchIdx : Passed index of the touch (0..1) on which we want to get the + * detailed information. + * @param pWeight : Pointer to to get the weight information of 'touchIdx'. + * @param pArea : Pointer to to get the sub-area information of 'touchIdx'. + * @param pEvent : Pointer to to get the event information of 'touchIdx'. + + * @retval None. + */ +void ft5336_TS_GetTouchInfo(uint16_t DeviceAddr, + uint32_t touchIdx, + uint32_t * pWeight, + uint32_t * pArea, + uint32_t * pEvent) +{ + volatile uint8_t ucReadData = 0; + uint8_t regAddressXHigh = 0; + uint8_t regAddressPWeight = 0; + uint8_t regAddressPMisc = 0; + + if(touchIdx < ft5336_handle.currActiveTouchNb) + { + switch(touchIdx) + { + case 0 : + regAddressXHigh = FT5336_P1_XH_REG; + regAddressPWeight = FT5336_P1_WEIGHT_REG; + regAddressPMisc = FT5336_P1_MISC_REG; + break; + + case 1 : + regAddressXHigh = FT5336_P2_XH_REG; + regAddressPWeight = FT5336_P2_WEIGHT_REG; + regAddressPMisc = FT5336_P2_MISC_REG; + break; + + case 2 : + regAddressXHigh = FT5336_P3_XH_REG; + regAddressPWeight = FT5336_P3_WEIGHT_REG; + regAddressPMisc = FT5336_P3_MISC_REG; + break; + + case 3 : + regAddressXHigh = FT5336_P4_XH_REG; + regAddressPWeight = FT5336_P4_WEIGHT_REG; + regAddressPMisc = FT5336_P4_MISC_REG; + break; + + case 4 : + regAddressXHigh = FT5336_P5_XH_REG; + regAddressPWeight = FT5336_P5_WEIGHT_REG; + regAddressPMisc = FT5336_P5_MISC_REG; + break; + + case 5 : + regAddressXHigh = FT5336_P6_XH_REG; + regAddressPWeight = FT5336_P6_WEIGHT_REG; + regAddressPMisc = FT5336_P6_MISC_REG; + break; + + case 6 : + regAddressXHigh = FT5336_P7_XH_REG; + regAddressPWeight = FT5336_P7_WEIGHT_REG; + regAddressPMisc = FT5336_P7_MISC_REG; + break; + + case 7 : + regAddressXHigh = FT5336_P8_XH_REG; + regAddressPWeight = FT5336_P8_WEIGHT_REG; + regAddressPMisc = FT5336_P8_MISC_REG; + break; + + case 8 : + regAddressXHigh = FT5336_P9_XH_REG; + regAddressPWeight = FT5336_P9_WEIGHT_REG; + regAddressPMisc = FT5336_P9_MISC_REG; + break; + + case 9 : + regAddressXHigh = FT5336_P10_XH_REG; + regAddressPWeight = FT5336_P10_WEIGHT_REG; + regAddressPMisc = FT5336_P10_MISC_REG; + break; + + default : + break; + + } /* end switch(touchIdx) */ + + /* Read Event Id of touch index */ + ucReadData = TS_IO_Read(DeviceAddr, regAddressXHigh); + * pEvent = (ucReadData & FT5336_TOUCH_EVT_FLAG_MASK) >> FT5336_TOUCH_EVT_FLAG_SHIFT; + + /* Read weight of touch index */ + ucReadData = TS_IO_Read(DeviceAddr, regAddressPWeight); + * pWeight = (ucReadData & FT5336_TOUCH_WEIGHT_MASK) >> FT5336_TOUCH_WEIGHT_SHIFT; + + /* Read area of touch index */ + ucReadData = TS_IO_Read(DeviceAddr, regAddressPMisc); + * pArea = (ucReadData & FT5336_TOUCH_AREA_MASK) >> FT5336_TOUCH_AREA_SHIFT; + + } /* of if(touchIdx < ft5336_handle.currActiveTouchNb) */ +} + +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +/** @defgroup ft5336_Static_Function_Body + * @{ + */ + +/* Static functions bodies-----------------------------------------------*/ + + +/** + * @brief Return the status of I2C was initialized or not. + * @param None. + * @retval : I2C initialization status. + */ +static uint8_t ft5336_Get_I2C_InitializedStatus(void) +{ + return(ft5336_handle.i2cInitialized); +} + +/** + * @brief I2C initialize if needed. + * @param None. + * @retval : None. + */ +static void ft5336_I2C_InitializeIfRequired(void) +{ + if(ft5336_Get_I2C_InitializedStatus() == FT5336_I2C_NOT_INITIALIZED) + { + /* Initialize TS IO BUS layer (I2C) */ + TS_IO_Init(); + + /* Set state to initialized */ + ft5336_handle.i2cInitialized = FT5336_I2C_INITIALIZED; + } +} + +/** + * @brief Basic static configuration of TouchScreen + * @param DeviceAddr: FT5336 Device address for communication on I2C Bus. + * @retval Status FT5336_STATUS_OK or FT5336_STATUS_NOT_OK. + */ +static uint32_t ft5336_TS_Configure(uint16_t DeviceAddr) +{ + uint32_t status = FT5336_STATUS_OK; + + /* Nothing special to be done for FT5336 */ + + return(status); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ft5336/ft5336.h b/src/port_stm32f7/common/bsp_drivers/Components/ft5336/ft5336.h new file mode 100644 index 00000000..2a756afa --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ft5336/ft5336.h @@ -0,0 +1,538 @@ +/** + ****************************************************************************** + * @file ft5336.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for the + * ft5336.c Touch screen driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __FT5336_H +#define __FT5336_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Set Multi-touch as supported */ +#if !defined(TS_MONO_TOUCH_SUPPORTED) +#define TS_MULTI_TOUCH_SUPPORTED 1 +#endif /* TS_MONO_TOUCH_SUPPORTED */ + +/* Includes ------------------------------------------------------------------*/ +#include "../Common/ts.h" + +/* Macros --------------------------------------------------------------------*/ + +#if defined(FT5336_ENABLE_ASSERT) +/* Assert activated */ +#define FT5336_ASSERT(__condition__) do { if(__condition__) \ + { \ + while(1); \ + } \ + }while(0) +#else +/* Assert not activated : macro has no effect */ +#define FT5336_ASSERT(__condition__) do { if(__condition__) \ + { \ + ; \ + } \ + }while(0) +#endif /* FT5336_ENABLE_ASSERT == 1 */ + +/** @typedef ft5336_handle_TypeDef + * ft5336 Handle definition. + */ +typedef struct +{ + uint8_t i2cInitialized; + + /* field holding the current number of simultaneous active touches */ + uint8_t currActiveTouchNb; + + /* field holding the touch index currently managed */ + uint8_t currActiveTouchIdx; + +} ft5336_handle_TypeDef; + + /** @addtogroup BSP + * @{ + */ + + /** @addtogroup Component + * @{ + */ + + /** @defgroup FT5336 + * @{ + */ + + /* Exported types ------------------------------------------------------------*/ + + /** @defgroup FT5336_Exported_Types + * @{ + */ + + /* Exported constants --------------------------------------------------------*/ + + /** @defgroup FT5336_Exported_Constants + * @{ + */ + + /* I2C Slave address of touchscreen FocalTech FT5336 */ +#define FT5336_I2C_SLAVE_ADDRESS ((uint8_t)0x70) + + /* Maximum border values of the touchscreen pad */ +#define FT5336_MAX_WIDTH ((uint16_t)480) /* Touchscreen pad max width */ +#define FT5336_MAX_HEIGHT ((uint16_t)272) /* Touchscreen pad max height */ + + /* Possible values of driver functions return status */ +#define FT5336_STATUS_OK ((uint8_t)0x00) +#define FT5336_STATUS_NOT_OK ((uint8_t)0x01) + + /* Possible values of global variable 'TS_I2C_Initialized' */ +#define FT5336_I2C_NOT_INITIALIZED ((uint8_t)0x00) +#define FT5336_I2C_INITIALIZED ((uint8_t)0x01) + + /* Max detectable simultaneous touches */ +#define FT5336_MAX_DETECTABLE_TOUCH ((uint8_t)0x05) + + /** + * @brief : Definitions for FT5336 I2C register addresses on 8 bit + **/ + + /* Current mode register of the FT5336 (R/W) */ +#define FT5336_DEV_MODE_REG ((uint8_t)0x00) + + /* Possible values of FT5336_DEV_MODE_REG */ +#define FT5336_DEV_MODE_WORKING ((uint8_t)0x00) +#define FT5336_DEV_MODE_FACTORY ((uint8_t)0x04) + +#define FT5336_DEV_MODE_MASK ((uint8_t)0x07) +#define FT5336_DEV_MODE_SHIFT ((uint8_t)0x04) + + /* Gesture ID register */ +#define FT5336_GEST_ID_REG ((uint8_t)0x01) + + /* Possible values of FT5336_GEST_ID_REG */ +#define FT5336_GEST_ID_NO_GESTURE ((uint8_t)0x00) +#define FT5336_GEST_ID_MOVE_UP ((uint8_t)0x10) +#define FT5336_GEST_ID_MOVE_RIGHT ((uint8_t)0x14) +#define FT5336_GEST_ID_MOVE_DOWN ((uint8_t)0x18) +#define FT5336_GEST_ID_MOVE_LEFT ((uint8_t)0x1C) +#define FT5336_GEST_ID_SINGLE_CLICK ((uint8_t)0x20) +#define FT5336_GEST_ID_DOUBLE_CLICK ((uint8_t)0x22) +#define FT5336_GEST_ID_ROTATE_CLOCKWISE ((uint8_t)0x28) +#define FT5336_GEST_ID_ROTATE_C_CLOCKWISE ((uint8_t)0x29) +#define FT5336_GEST_ID_ZOOM_IN ((uint8_t)0x40) +#define FT5336_GEST_ID_ZOOM_OUT ((uint8_t)0x49) + + /* Touch Data Status register : gives number of active touch points (0..5) */ +#define FT5336_TD_STAT_REG ((uint8_t)0x02) + + /* Values related to FT5336_TD_STAT_REG */ +#define FT5336_TD_STAT_MASK ((uint8_t)0x0F) +#define FT5336_TD_STAT_SHIFT ((uint8_t)0x00) + + /* Values Pn_XH and Pn_YH related */ +#define FT5336_TOUCH_EVT_FLAG_PRESS_DOWN ((uint8_t)0x00) +#define FT5336_TOUCH_EVT_FLAG_LIFT_UP ((uint8_t)0x01) +#define FT5336_TOUCH_EVT_FLAG_CONTACT ((uint8_t)0x02) +#define FT5336_TOUCH_EVT_FLAG_NO_EVENT ((uint8_t)0x03) + +#define FT5336_TOUCH_EVT_FLAG_SHIFT ((uint8_t)0x06) +#define FT5336_TOUCH_EVT_FLAG_MASK ((uint8_t)(3 << FT5336_TOUCH_EVT_FLAG_SHIFT)) + +#define FT5336_TOUCH_POS_MSB_MASK ((uint8_t)0x0F) +#define FT5336_TOUCH_POS_MSB_SHIFT ((uint8_t)0x00) + + /* Values Pn_XL and Pn_YL related */ +#define FT5336_TOUCH_POS_LSB_MASK ((uint8_t)0xFF) +#define FT5336_TOUCH_POS_LSB_SHIFT ((uint8_t)0x00) + +#define FT5336_P1_XH_REG ((uint8_t)0x03) +#define FT5336_P1_XL_REG ((uint8_t)0x04) +#define FT5336_P1_YH_REG ((uint8_t)0x05) +#define FT5336_P1_YL_REG ((uint8_t)0x06) + +/* Touch Pressure register value (R) */ +#define FT5336_P1_WEIGHT_REG ((uint8_t)0x07) + +/* Values Pn_WEIGHT related */ +#define FT5336_TOUCH_WEIGHT_MASK ((uint8_t)0xFF) +#define FT5336_TOUCH_WEIGHT_SHIFT ((uint8_t)0x00) + +/* Touch area register */ +#define FT5336_P1_MISC_REG ((uint8_t)0x08) + +/* Values related to FT5336_Pn_MISC_REG */ +#define FT5336_TOUCH_AREA_MASK ((uint8_t)(0x04 << 4)) +#define FT5336_TOUCH_AREA_SHIFT ((uint8_t)0x04) + +#define FT5336_P2_XH_REG ((uint8_t)0x09) +#define FT5336_P2_XL_REG ((uint8_t)0x0A) +#define FT5336_P2_YH_REG ((uint8_t)0x0B) +#define FT5336_P2_YL_REG ((uint8_t)0x0C) +#define FT5336_P2_WEIGHT_REG ((uint8_t)0x0D) +#define FT5336_P2_MISC_REG ((uint8_t)0x0E) + +#define FT5336_P3_XH_REG ((uint8_t)0x0F) +#define FT5336_P3_XL_REG ((uint8_t)0x10) +#define FT5336_P3_YH_REG ((uint8_t)0x11) +#define FT5336_P3_YL_REG ((uint8_t)0x12) +#define FT5336_P3_WEIGHT_REG ((uint8_t)0x13) +#define FT5336_P3_MISC_REG ((uint8_t)0x14) + +#define FT5336_P4_XH_REG ((uint8_t)0x15) +#define FT5336_P4_XL_REG ((uint8_t)0x16) +#define FT5336_P4_YH_REG ((uint8_t)0x17) +#define FT5336_P4_YL_REG ((uint8_t)0x18) +#define FT5336_P4_WEIGHT_REG ((uint8_t)0x19) +#define FT5336_P4_MISC_REG ((uint8_t)0x1A) + +#define FT5336_P5_XH_REG ((uint8_t)0x1B) +#define FT5336_P5_XL_REG ((uint8_t)0x1C) +#define FT5336_P5_YH_REG ((uint8_t)0x1D) +#define FT5336_P5_YL_REG ((uint8_t)0x1E) +#define FT5336_P5_WEIGHT_REG ((uint8_t)0x1F) +#define FT5336_P5_MISC_REG ((uint8_t)0x20) + +#define FT5336_P6_XH_REG ((uint8_t)0x21) +#define FT5336_P6_XL_REG ((uint8_t)0x22) +#define FT5336_P6_YH_REG ((uint8_t)0x23) +#define FT5336_P6_YL_REG ((uint8_t)0x24) +#define FT5336_P6_WEIGHT_REG ((uint8_t)0x25) +#define FT5336_P6_MISC_REG ((uint8_t)0x26) + +#define FT5336_P7_XH_REG ((uint8_t)0x27) +#define FT5336_P7_XL_REG ((uint8_t)0x28) +#define FT5336_P7_YH_REG ((uint8_t)0x29) +#define FT5336_P7_YL_REG ((uint8_t)0x2A) +#define FT5336_P7_WEIGHT_REG ((uint8_t)0x2B) +#define FT5336_P7_MISC_REG ((uint8_t)0x2C) + +#define FT5336_P8_XH_REG ((uint8_t)0x2D) +#define FT5336_P8_XL_REG ((uint8_t)0x2E) +#define FT5336_P8_YH_REG ((uint8_t)0x2F) +#define FT5336_P8_YL_REG ((uint8_t)0x30) +#define FT5336_P8_WEIGHT_REG ((uint8_t)0x31) +#define FT5336_P8_MISC_REG ((uint8_t)0x32) + +#define FT5336_P9_XH_REG ((uint8_t)0x33) +#define FT5336_P9_XL_REG ((uint8_t)0x34) +#define FT5336_P9_YH_REG ((uint8_t)0x35) +#define FT5336_P9_YL_REG ((uint8_t)0x36) +#define FT5336_P9_WEIGHT_REG ((uint8_t)0x37) +#define FT5336_P9_MISC_REG ((uint8_t)0x38) + +#define FT5336_P10_XH_REG ((uint8_t)0x39) +#define FT5336_P10_XL_REG ((uint8_t)0x3A) +#define FT5336_P10_YH_REG ((uint8_t)0x3B) +#define FT5336_P10_YL_REG ((uint8_t)0x3C) +#define FT5336_P10_WEIGHT_REG ((uint8_t)0x3D) +#define FT5336_P10_MISC_REG ((uint8_t)0x3E) + + /* Threshold for touch detection */ +#define FT5336_TH_GROUP_REG ((uint8_t)0x80) + + /* Values FT5336_TH_GROUP_REG : threshold related */ +#define FT5336_THRESHOLD_MASK ((uint8_t)0xFF) +#define FT5336_THRESHOLD_SHIFT ((uint8_t)0x00) + + /* Filter function coefficients */ +#define FT5336_TH_DIFF_REG ((uint8_t)0x85) + + /* Control register */ +#define FT5336_CTRL_REG ((uint8_t)0x86) + + /* Values related to FT5336_CTRL_REG */ + + /* Will keep the Active mode when there is no touching */ +#define FT5336_CTRL_KEEP_ACTIVE_MODE ((uint8_t)0x00) + + /* Switching from Active mode to Monitor mode automatically when there is no touching */ +#define FT5336_CTRL_KEEP_AUTO_SWITCH_MONITOR_MODE ((uint8_t)0x01 + + /* The time period of switching from Active mode to Monitor mode when there is no touching */ +#define FT5336_TIMEENTERMONITOR_REG ((uint8_t)0x87) + + /* Report rate in Active mode */ +#define FT5336_PERIODACTIVE_REG ((uint8_t)0x88) + + /* Report rate in Monitor mode */ +#define FT5336_PERIODMONITOR_REG ((uint8_t)0x89) + + /* The value of the minimum allowed angle while Rotating gesture mode */ +#define FT5336_RADIAN_VALUE_REG ((uint8_t)0x91) + + /* Maximum offset while Moving Left and Moving Right gesture */ +#define FT5336_OFFSET_LEFT_RIGHT_REG ((uint8_t)0x92) + + /* Maximum offset while Moving Up and Moving Down gesture */ +#define FT5336_OFFSET_UP_DOWN_REG ((uint8_t)0x93) + + /* Minimum distance while Moving Left and Moving Right gesture */ +#define FT5336_DISTANCE_LEFT_RIGHT_REG ((uint8_t)0x94) + + /* Minimum distance while Moving Up and Moving Down gesture */ +#define FT5336_DISTANCE_UP_DOWN_REG ((uint8_t)0x95) + + /* Maximum distance while Zoom In and Zoom Out gesture */ +#define FT5336_DISTANCE_ZOOM_REG ((uint8_t)0x96) + + /* High 8-bit of LIB Version info */ +#define FT5336_LIB_VER_H_REG ((uint8_t)0xA1) + + /* Low 8-bit of LIB Version info */ +#define FT5336_LIB_VER_L_REG ((uint8_t)0xA2) + + /* Chip Selecting */ +#define FT5336_CIPHER_REG ((uint8_t)0xA3) + + /* Interrupt mode register (used when in interrupt mode) */ +#define FT5336_GMODE_REG ((uint8_t)0xA4) + +#define FT5336_G_MODE_INTERRUPT_MASK ((uint8_t)0x03) +#define FT5336_G_MODE_INTERRUPT_SHIFT ((uint8_t)0x00) + + /* Possible values of FT5336_GMODE_REG */ +#define FT5336_G_MODE_INTERRUPT_POLLING ((uint8_t)0x00) +#define FT5336_G_MODE_INTERRUPT_TRIGGER ((uint8_t)0x01) + + /* Current power mode the FT5336 system is in (R) */ +#define FT5336_PWR_MODE_REG ((uint8_t)0xA5) + + /* FT5336 firmware version */ +#define FT5336_FIRMID_REG ((uint8_t)0xA6) + + /* FT5336 Chip identification register */ +#define FT5336_CHIP_ID_REG ((uint8_t)0xA8) + + /* Possible values of FT5336_CHIP_ID_REG */ +#define FT5336_ID_VALUE ((uint8_t)0x51) + + /* Release code version */ +#define FT5336_RELEASE_CODE_ID_REG ((uint8_t)0xAF) + + /* Current operating mode the FT5336 system is in (R) */ +#define FT5336_STATE_REG ((uint8_t)0xBC) + + /** + * @} + */ + + /* Exported macro ------------------------------------------------------------*/ + + /** @defgroup ft5336_Exported_Macros + * @{ + */ + + /* Exported functions --------------------------------------------------------*/ + + /** @defgroup ft5336_Exported_Functions + * @{ + */ + + /** + * @brief ft5336 Control functions + */ + + +/** + * @brief Initialize the ft5336 communication bus + * from MCU to FT5336 : ie I2C channel initialization (if required). + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT5336). + * @retval None + */ +void ft5336_Init(uint16_t DeviceAddr); + +/** + * @brief Software Reset the ft5336. + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT5336). + * @retval None + */ +void ft5336_Reset(uint16_t DeviceAddr); + +/** + * @brief Read the ft5336 device ID, pre initialize I2C in case of need to be + * able to read the FT5336 device ID, and verify this is a FT5336. + * @param DeviceAddr: I2C FT5336 Slave address. + * @retval The Device ID (two bytes). + */ +uint16_t ft5336_ReadID(uint16_t DeviceAddr); + +/** + * @brief Configures the touch Screen IC device to start detecting touches + * @param DeviceAddr: Device address on communication Bus (I2C slave address). + * @retval None. + */ +void ft5336_TS_Start(uint16_t DeviceAddr); + +/** + * @brief Return if there is touches detected or not. + * Try to detect new touches and forget the old ones (reset internal global + * variables). + * @param DeviceAddr: Device address on communication Bus. + * @retval : Number of active touches detected (can be 0, 1 or 2). + */ +uint8_t ft5336_TS_DetectTouch(uint16_t DeviceAddr); + +/** + * @brief Get the touch screen X and Y positions values + * Manage multi touch thanks to touch Index global + * variable 'ft5336_handle.currActiveTouchIdx'. + * @param DeviceAddr: Device address on communication Bus. + * @param X: Pointer to X position value + * @param Y: Pointer to Y position value + * @retval None. + */ +void ft5336_TS_GetXY(uint16_t DeviceAddr, uint16_t *X, uint16_t *Y); + +/** + * @brief Configure the FT5336 device to generate IT on given INT pin + * connected to MCU as EXTI. + * @param DeviceAddr: Device address on communication Bus (Slave I2C address of FT5336). + * @retval None + */ +void ft5336_TS_EnableIT(uint16_t DeviceAddr); + +/** + * @brief Configure the FT5336 device to stop generating IT on the given INT pin + * connected to MCU as EXTI. + * @param DeviceAddr: Device address on communication Bus (Slave I2C address of FT5336). + * @retval None + */ +void ft5336_TS_DisableIT(uint16_t DeviceAddr); + +/** + * @brief Get IT status from FT5336 interrupt status registers + * Should be called Following an EXTI coming to the MCU to know the detailed + * reason of the interrupt. + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT5336). + * @retval TS interrupts status + */ +uint8_t ft5336_TS_ITStatus (uint16_t DeviceAddr); + +/** + * @brief Clear IT status in FT5336 interrupt status clear registers + * Should be called Following an EXTI coming to the MCU. + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT5336). + * @retval TS interrupts status + */ +void ft5336_TS_ClearIT (uint16_t DeviceAddr); + +/**** NEW FEATURES enabled when Multi-touch support is enabled ****/ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + +/** + * @brief Get the last touch gesture identification (zoom, move up/down...). + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT5336). + * @param pGestureId : Pointer to get last touch gesture Identification. + * @retval None. + */ +void ft5336_TS_GetGestureID(uint16_t DeviceAddr, uint32_t * pGestureId); + +/** + * @brief Get the touch detailed informations on touch number 'touchIdx' (0..1) + * This touch detailed information contains : + * - weight that was applied to this touch + * - sub-area of the touch in the touch panel + * - event of linked to the touch (press down, lift up, ...) + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT5336). + * @param touchIdx : Passed index of the touch (0..1) on which we want to get the + * detailed information. + * @param pWeight : Pointer to to get the weight information of 'touchIdx'. + * @param pArea : Pointer to to get the sub-area information of 'touchIdx'. + * @param pEvent : Pointer to to get the event information of 'touchIdx'. + + * @retval None. + */ +void ft5336_TS_GetTouchInfo(uint16_t DeviceAddr, + uint32_t touchIdx, + uint32_t * pWeight, + uint32_t * pArea, + uint32_t * pEvent); + +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +/* Imported TS IO functions --------------------------------------------------------*/ + +/** @defgroup ft5336_Imported_Functions + * @{ + */ + +/* TouchScreen (TS) external IO functions */ +extern void TS_IO_Init(void); +extern void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +extern uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg); +extern void TS_IO_Delay(uint32_t Delay); + + /** + * @} + */ + + /* Imported global variables --------------------------------------------------------*/ + + /** @defgroup ft5336_Imported_Globals + * @{ + */ + + +/* Touch screen driver structure */ +extern TS_DrvTypeDef ft5336_ts_drv; + + /** + * @} + */ + +#ifdef __cplusplus +} +#endif +#endif /* __FT5336_H */ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ft6x06/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/ft6x06/Release_Notes.html new file mode 100644 index 00000000..bb6796b9 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ft6x06/Release_Notes.html @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + Release Notes for STM32 BSP Components Drivers + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for FT6X06 Component Driver

+

Copyright +2017 STMicroelectronics

+

+
+

 

+ + + + + + +

Update History

+

V1.0.2 +/ 07-April-2017

+ + + + +

Main +Changes

+ + + + + + + + + + + + +
    +
  • Update comments to be used for PDSC generation
  • +
+

V1.0.1 +/ 03-May-2016

+ + +

Main +Changes

+ + + + + + + + + + +
    +
  • Add support of FT6x36 Touch controller
  • +
+

V1.0.0 +/ 03-August-2015

+ +

Main +Changes

+ + + + + + + + + +
  • First official release of FT6X06 TS component driver

License

+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+
For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32
+

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ft6x06/ft6x06.c b/src/port_stm32f7/common/bsp_drivers/Components/ft6x06/ft6x06.c new file mode 100644 index 00000000..56cb4300 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ft6x06/ft6x06.c @@ -0,0 +1,512 @@ +/** + ****************************************************************************** + * @file ft6x06.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the FT6X06 + * IO Expander devices. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "ft6x06.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Component + * @{ + */ + +/** @defgroup FT6X06 + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ + +/** @defgroup FT6X06_Private_Defines FT6X06 Private Defines + * @{ + */ +#define FT6x06_MAX_INSTANCE 2 +/** + * @} + */ + +/* Private macro -------------------------------------------------------------*/ + +/** @defgroup FT6X06_Private_Variables FT6X06 Private Variables + * @{ + */ + +/* Touch screen driver structure initialization */ +TS_DrvTypeDef ft6x06_ts_drv = +{ + ft6x06_Init, + ft6x06_ReadID, + ft6x06_Reset, + + ft6x06_TS_Start, + ft6x06_TS_DetectTouch, + ft6x06_TS_GetXY, + + ft6x06_TS_EnableIT, + ft6x06_TS_ClearIT, + ft6x06_TS_ITStatus, + ft6x06_TS_DisableIT +}; + +/* ft6x06 instances by address */ +uint8_t ft6x06[FT6x06_MAX_INSTANCE] = {0}; + +/* Global ft6x06 handle */ +static ft6x06_handle_TypeDef ft6x06_handle = { FT6206_I2C_NOT_INITIALIZED, 0, 0}; + +/** + * @} + */ + +/** @defgroup ft6x06_Private_Function_Prototypes ft6x06 Private Function Prototypes + * @{ + */ +static uint8_t ft6x06_GetInstance(uint16_t DeviceAddr); +/* Private functions prototypes-----------------------------------------------*/ +#if (TS_AUTO_CALIBRATION_SUPPORTED == 1) +/** + * @brief Start TouchScreen calibration phase + * @param DeviceAddr: FT6206 Device address for communication on I2C Bus. + * @retval Status FT6206_STATUS_OK or FT6206_STATUS_NOT_OK. + */ +static uint32_t ft6x06_TS_Calibration(uint16_t DeviceAddr); +#endif /* TS_AUTO_CALIBRATION_SUPPORTED == 1 */ + +/** + * @brief Basic static configuration of TouchScreen + * @param DeviceAddr: FT6206 Device address for communication on I2C Bus. + * @retval Status FT6206_STATUS_OK or FT6206_STATUS_NOT_OK. + */ +static uint32_t ft6x06_TS_Configure(uint16_t DeviceAddr); + +/** + * @} + */ + +/** @defgroup ft6x06_Private_Functions ft6x06 Private Functions + * @{ + */ + +/** + * @brief Initialize the ft6x06 communication bus + * from MCU to FT6206 : ie I2C channel initialization (if required). + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6206). + * @retval None + */ +void ft6x06_Init(uint16_t DeviceAddr) +{ + uint8_t instance; + uint8_t empty; + + /* Check if device instance already exists */ + instance = ft6x06_GetInstance(DeviceAddr); + + /* To prevent double initialization */ + if(instance == 0xFF) + { + /* Look for empty instance */ + empty = ft6x06_GetInstance(0); + + if(empty < FT6x06_MAX_INSTANCE) + { + /* Register the current device instance */ + ft6x06[empty] = DeviceAddr; + + /* Initialize IO BUS layer */ + TS_IO_Init(); + } + } +} + +/** + * @brief Software Reset the ft6x06. + * @note : Not applicable to FT6206. + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6206). + * @retval None + */ +void ft6x06_Reset(uint16_t DeviceAddr) +{ + /* Do nothing */ + /* No software reset sequence available in FT6206 IC */ +} + +/** + * @brief Read the ft6x06 device ID, pre initialize I2C in case of need to be + * able to read the FT6206 device ID, and verify this is a FT6206. + * @param DeviceAddr: I2C FT6x06 Slave address. + * @retval The Device ID (two bytes). + */ +uint16_t ft6x06_ReadID(uint16_t DeviceAddr) +{ + /* Initialize I2C link if needed */ + TS_IO_Init(); + + /* Return the device ID value */ + return (TS_IO_Read(DeviceAddr, FT6206_CHIP_ID_REG)); +} + +/** + * @brief Configures the touch Screen IC device to start detecting touches + * It goes through an internal calibration process (Hw calibration sequence of + * the touch screen). + * @param DeviceAddr: Device address on communication Bus (I2C slave address). + * @retval None. + */ +void ft6x06_TS_Start(uint16_t DeviceAddr) +{ +#if (TS_AUTO_CALIBRATION_SUPPORTED == 1) + /* Hw Calibration sequence start : should be done once after each power up */ + /* This is called internal calibration of the touch screen */ + ft6x06_TS_Calibration(DeviceAddr); +#endif + /* Minimum static configuration of FT6206 */ + ft6x06_TS_Configure(DeviceAddr); + + /* By default set FT6206 IC in Polling mode : no INT generation on FT6206 for new touch available */ + /* Note TS_INT is active low */ + ft6x06_TS_DisableIT(DeviceAddr); +} + +/** + * @brief Return if there is touches detected or not. + * Try to detect new touches and forget the old ones (reset internal global + * variables). + * @param DeviceAddr: Device address on communication Bus. + * @retval : Number of active touches detected (can be 0, 1 or 2). + */ +uint8_t ft6x06_TS_DetectTouch(uint16_t DeviceAddr) +{ + volatile uint8_t nbTouch = 0; + + /* Read register FT6206_TD_STAT_REG to check number of touches detection */ + nbTouch = TS_IO_Read(DeviceAddr, FT6206_TD_STAT_REG); + nbTouch &= FT6206_TD_STAT_MASK; + + if(nbTouch > FT6206_MAX_DETECTABLE_TOUCH) + { + /* If invalid number of touch detected, set it to zero */ + nbTouch = 0; + } + + /* Update ft6x06 driver internal global : current number of active touches */ + ft6x06_handle.currActiveTouchNb = nbTouch; + + /* Reset current active touch index on which to work on */ + ft6x06_handle.currActiveTouchIdx = 0; + + return(nbTouch); +} + +/** + * @brief Get the touch screen X and Y positions values + * Manage multi touch thanks to touch Index global + * variable 'ft6x06_handle.currActiveTouchIdx'. + * @param DeviceAddr: Device address on communication Bus. + * @param X: Pointer to X position value + * @param Y: Pointer to Y position value + * @retval None. + */ +void ft6x06_TS_GetXY(uint16_t DeviceAddr, uint16_t *X, uint16_t *Y) +{ + uint8_t regAddress = 0; + uint8_t dataxy[4]; + + if(ft6x06_handle.currActiveTouchIdx < ft6x06_handle.currActiveTouchNb) + { + switch(ft6x06_handle.currActiveTouchIdx) + { + case 0 : + regAddress = FT6206_P1_XH_REG; + break; + case 1 : + regAddress = FT6206_P2_XH_REG; + break; + + default : + break; + } + + /* Read X and Y positions */ + TS_IO_ReadMultiple(DeviceAddr, regAddress, dataxy, sizeof(dataxy)); + + /* Send back ready X position to caller */ + *X = ((dataxy[0] & FT6206_MSB_MASK) << 8) | (dataxy[1] & FT6206_LSB_MASK); + + /* Send back ready Y position to caller */ + *Y = ((dataxy[2] & FT6206_MSB_MASK) << 8) | (dataxy[3] & FT6206_LSB_MASK); + + ft6x06_handle.currActiveTouchIdx++; + } +} + +/** + * @brief Configure the FT6206 device to generate IT on given INT pin + * connected to MCU as EXTI. + * @param DeviceAddr: Device address on communication Bus (Slave I2C address of FT6206). + * @retval None + */ +void ft6x06_TS_EnableIT(uint16_t DeviceAddr) +{ + uint8_t regValue = 0; + regValue = (FT6206_G_MODE_INTERRUPT_TRIGGER & (FT6206_G_MODE_INTERRUPT_MASK >> FT6206_G_MODE_INTERRUPT_SHIFT)) << FT6206_G_MODE_INTERRUPT_SHIFT; + + /* Set interrupt trigger mode in FT6206_GMODE_REG */ + TS_IO_Write(DeviceAddr, FT6206_GMODE_REG, regValue); +} + +/** + * @brief Configure the FT6206 device to stop generating IT on the given INT pin + * connected to MCU as EXTI. + * @param DeviceAddr: Device address on communication Bus (Slave I2C address of FT6206). + * @retval None + */ +void ft6x06_TS_DisableIT(uint16_t DeviceAddr) +{ + uint8_t regValue = 0; + regValue = (FT6206_G_MODE_INTERRUPT_POLLING & (FT6206_G_MODE_INTERRUPT_MASK >> FT6206_G_MODE_INTERRUPT_SHIFT)) << FT6206_G_MODE_INTERRUPT_SHIFT; + + /* Set interrupt polling mode in FT6206_GMODE_REG */ + TS_IO_Write(DeviceAddr, FT6206_GMODE_REG, regValue); +} + +/** + * @brief Get IT status from FT6206 interrupt status registers + * Should be called Following an EXTI coming to the MCU to know the detailed + * reason of the interrupt. + * @note : This feature is not applicable to FT6206. + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6206). + * @retval TS interrupts status : always return 0 here + */ +uint8_t ft6x06_TS_ITStatus(uint16_t DeviceAddr) +{ + /* Always return 0 as feature not applicable to FT6206 */ + return 0; +} + +/** + * @brief Clear IT status in FT6206 interrupt status clear registers + * Should be called Following an EXTI coming to the MCU. + * @note : This feature is not applicable to FT6206. + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6206). + * @retval None + */ +void ft6x06_TS_ClearIT(uint16_t DeviceAddr) +{ + /* Nothing to be done here for FT6206 */ +} + +/**** NEW FEATURES enabled when Multi-touch support is enabled ****/ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +/** + * @brief Get the last touch gesture identification (zoom, move up/down...). + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6x06). + * @param pGestureId : Pointer to get last touch gesture Identification. + * @retval None. + */ +void ft6x06_TS_GetGestureID(uint16_t DeviceAddr, uint32_t * pGestureId) +{ + volatile uint8_t ucReadData = 0; + + ucReadData = TS_IO_Read(DeviceAddr, FT6206_GEST_ID_REG); + + * pGestureId = ucReadData; +} + +/** + * @brief Get the touch detailed informations on touch number 'touchIdx' (0..1) + * This touch detailed information contains : + * - weight that was applied to this touch + * - sub-area of the touch in the touch panel + * - event of linked to the touch (press down, lift up, ...) + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6x06). + * @param touchIdx : Passed index of the touch (0..1) on which we want to get the + * detailed information. + * @param pWeight : Pointer to to get the weight information of 'touchIdx'. + * @param pArea : Pointer to to get the sub-area information of 'touchIdx'. + * @param pEvent : Pointer to to get the event information of 'touchIdx'. + + * @retval None. + */ +void ft6x06_TS_GetTouchInfo(uint16_t DeviceAddr, + uint32_t touchIdx, + uint32_t * pWeight, + uint32_t * pArea, + uint32_t * pEvent) +{ + uint8_t regAddress = 0; + uint8_t dataxy[3]; + + if(touchIdx < ft6x06_handle.currActiveTouchNb) + { + switch(touchIdx) + { + case 0 : + regAddress = FT6206_P1_WEIGHT_REG; + break; + + case 1 : + regAddress = FT6206_P2_WEIGHT_REG; + break; + + default : + break; + + } /* end switch(touchIdx) */ + + /* Read weight, area and Event Id of touch index */ + TS_IO_ReadMultiple(DeviceAddr, regAddress, dataxy, sizeof(dataxy)); + + /* Return weight of touch index */ + * pWeight = (dataxy[0] & FT6206_TOUCH_WEIGHT_MASK) >> FT6206_TOUCH_WEIGHT_SHIFT; + /* Return area of touch index */ + * pArea = (dataxy[1] & FT6206_TOUCH_AREA_MASK) >> FT6206_TOUCH_AREA_SHIFT; + /* Return Event Id of touch index */ + * pEvent = (dataxy[2] & FT6206_TOUCH_EVT_FLAG_MASK) >> FT6206_TOUCH_EVT_FLAG_SHIFT; + + } /* of if(touchIdx < ft6x06_handle.currActiveTouchNb) */ +} + +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +#if (TS_AUTO_CALIBRATION_SUPPORTED == 1) +/** + * @brief Start TouchScreen calibration phase + * @param DeviceAddr: FT6206 Device address for communication on I2C Bus. + * @retval Status FT6206_STATUS_OK or FT6206_STATUS_NOT_OK. + */ +static uint32_t ft6x06_TS_Calibration(uint16_t DeviceAddr) +{ + uint32_t nbAttempt = 0; + volatile uint8_t ucReadData; + volatile uint8_t regValue; + uint32_t status = FT6206_STATUS_OK; + uint8_t bEndCalibration = 0; + + /* >> Calibration sequence start */ + + /* Switch FT6206 back to factory mode to calibrate */ + regValue = (FT6206_DEV_MODE_FACTORY & FT6206_DEV_MODE_MASK) << FT6206_DEV_MODE_SHIFT; + TS_IO_Write(DeviceAddr, FT6206_DEV_MODE_REG, regValue); /* 0x40 */ + + /* Read back the same register FT6206_DEV_MODE_REG */ + ucReadData = TS_IO_Read(DeviceAddr, FT6206_DEV_MODE_REG); + TS_IO_Delay(300); /* Wait 300 ms */ + + if(((ucReadData & (FT6206_DEV_MODE_MASK << FT6206_DEV_MODE_SHIFT)) >> FT6206_DEV_MODE_SHIFT) != FT6206_DEV_MODE_FACTORY ) + { + /* Return error to caller */ + return(FT6206_STATUS_NOT_OK); + } + + /* Start calibration command */ + TS_IO_Write(DeviceAddr, FT6206_TD_STAT_REG, 0x04); + TS_IO_Delay(300); /* Wait 300 ms */ + + /* 100 attempts to wait switch from factory mode (calibration) to working mode */ + for (nbAttempt=0; ((nbAttempt < 100) && (!bEndCalibration)) ; nbAttempt++) + { + ucReadData = TS_IO_Read(DeviceAddr, FT6206_DEV_MODE_REG); + ucReadData = (ucReadData & (FT6206_DEV_MODE_MASK << FT6206_DEV_MODE_SHIFT)) >> FT6206_DEV_MODE_SHIFT; + if(ucReadData == FT6206_DEV_MODE_WORKING) + { + /* Auto Switch to FT6206_DEV_MODE_WORKING : means calibration have ended */ + bEndCalibration = 1; /* exit for loop */ + } + + TS_IO_Delay(200); /* Wait 200 ms */ + } + + /* Calibration sequence end << */ + + return(status); +} +#endif /* TS_AUTO_CALIBRATION_SUPPORTED == 1 */ + +/** + * @brief Basic static configuration of TouchScreen + * @param DeviceAddr: FT6206 Device address for communication on I2C Bus. + * @retval Status FT6206_STATUS_OK or FT6206_STATUS_NOT_OK. + */ +static uint32_t ft6x06_TS_Configure(uint16_t DeviceAddr) +{ + uint32_t status = FT6206_STATUS_OK; + + /* Nothing special to be done for FT6206 */ + + return(status); +} + +/** + * @brief Check if the device instance of the selected address is already registered + * and return its index + * @param DeviceAddr: Device address on communication Bus. + * @retval Index of the device instance if registered, 0xFF if not. + */ +static uint8_t ft6x06_GetInstance(uint16_t DeviceAddr) +{ + uint8_t idx = 0; + + /* Check all the registered instances */ + for(idx = 0; idx < FT6x06_MAX_INSTANCE ; idx ++) + { + if(ft6x06[idx] == DeviceAddr) + { + return idx; + } + } + + return 0xFF; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ft6x06/ft6x06.h b/src/port_stm32f7/common/bsp_drivers/Components/ft6x06/ft6x06.h new file mode 100644 index 00000000..67ac74c5 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ft6x06/ft6x06.h @@ -0,0 +1,469 @@ +/** + ****************************************************************************** + * @file ft6x06.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for the + * ft6x06.c IO expander driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __FT6X06_H +#define __FT6X06_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Set Multi-touch as non supported */ +#ifndef TS_MULTI_TOUCH_SUPPORTED + #define TS_MULTI_TOUCH_SUPPORTED 0 +#endif + +/* Set Auto-calibration as non supported */ +#ifndef TS_AUTO_CALIBRATION_SUPPORTED + #define TS_AUTO_CALIBRATION_SUPPORTED 0 +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "../Common/ts.h" + +/* Macros --------------------------------------------------------------------*/ + +/** @typedef ft6x06_handle_TypeDef + * ft6x06 Handle definition. + */ +typedef struct +{ + uint8_t i2cInitialized; + + /* field holding the current number of simultaneous active touches */ + uint8_t currActiveTouchNb; + + /* field holding the touch index currently managed */ + uint8_t currActiveTouchIdx; + +} ft6x06_handle_TypeDef; + + /** @addtogroup BSP + * @{ + */ + + /** @addtogroup Component + * @{ + */ + + /** @defgroup FT6X06 + * @{ + */ + + /* Exported types ------------------------------------------------------------*/ + + /** @defgroup FT6X06_Exported_Types + * @{ + */ + + /* Exported constants --------------------------------------------------------*/ + + /** @defgroup FT6X06_Exported_Constants + * @{ + */ + + /* Maximum border values of the touchscreen pad */ +#define FT_6206_MAX_WIDTH ((uint16_t)800) /* Touchscreen pad max width */ +#define FT_6206_MAX_HEIGHT ((uint16_t)480) /* Touchscreen pad max height */ + + /* Touchscreen pad max width and height values for FT6x36 Touch*/ +#define FT_6206_MAX_WIDTH_HEIGHT ((uint16_t)240) + + /* Possible values of driver functions return status */ +#define FT6206_STATUS_OK 0 +#define FT6206_STATUS_NOT_OK 1 + + /* Possible values of global variable 'TS_I2C_Initialized' */ +#define FT6206_I2C_NOT_INITIALIZED 0 +#define FT6206_I2C_INITIALIZED 1 + + /* Max detectable simultaneous touches */ +#define FT6206_MAX_DETECTABLE_TOUCH 2 + + /** + * @brief : Definitions for FT6206 I2C register addresses on 8 bit + **/ + + /* Current mode register of the FT6206 (R/W) */ +#define FT6206_DEV_MODE_REG 0x00 + + /* Possible values of FT6206_DEV_MODE_REG */ +#define FT6206_DEV_MODE_WORKING 0x00 +#define FT6206_DEV_MODE_FACTORY 0x04 + +#define FT6206_DEV_MODE_MASK 0x7 +#define FT6206_DEV_MODE_SHIFT 4 + + /* Gesture ID register */ +#define FT6206_GEST_ID_REG 0x01 + + /* Possible values of FT6206_GEST_ID_REG */ +#define FT6206_GEST_ID_NO_GESTURE 0x00 +#define FT6206_GEST_ID_MOVE_UP 0x10 +#define FT6206_GEST_ID_MOVE_RIGHT 0x14 +#define FT6206_GEST_ID_MOVE_DOWN 0x18 +#define FT6206_GEST_ID_MOVE_LEFT 0x1C +#define FT6206_GEST_ID_ZOOM_IN 0x48 +#define FT6206_GEST_ID_ZOOM_OUT 0x49 + + /* Touch Data Status register : gives number of active touch points (0..2) */ +#define FT6206_TD_STAT_REG 0x02 + + /* Values related to FT6206_TD_STAT_REG */ +#define FT6206_TD_STAT_MASK 0x0F +#define FT6206_TD_STAT_SHIFT 0x00 + + /* Values Pn_XH and Pn_YH related */ +#define FT6206_TOUCH_EVT_FLAG_PRESS_DOWN 0x00 +#define FT6206_TOUCH_EVT_FLAG_LIFT_UP 0x01 +#define FT6206_TOUCH_EVT_FLAG_CONTACT 0x02 +#define FT6206_TOUCH_EVT_FLAG_NO_EVENT 0x03 + +#define FT6206_TOUCH_EVT_FLAG_SHIFT 6 +#define FT6206_TOUCH_EVT_FLAG_MASK (3 << FT6206_TOUCH_EVT_FLAG_SHIFT) + +#define FT6206_MSB_MASK 0x0F +#define FT6206_MSB_SHIFT 0 + + /* Values Pn_XL and Pn_YL related */ +#define FT6206_LSB_MASK 0xFF +#define FT6206_LSB_SHIFT 0 + +#define FT6206_P1_XH_REG 0x03 +#define FT6206_P1_XL_REG 0x04 +#define FT6206_P1_YH_REG 0x05 +#define FT6206_P1_YL_REG 0x06 + + /* Touch Pressure register value (R) */ +#define FT6206_P1_WEIGHT_REG 0x07 + + /* Values Pn_WEIGHT related */ +#define FT6206_TOUCH_WEIGHT_MASK 0xFF +#define FT6206_TOUCH_WEIGHT_SHIFT 0 + + /* Touch area register */ +#define FT6206_P1_MISC_REG 0x08 + + /* Values related to FT6206_Pn_MISC_REG */ +#define FT6206_TOUCH_AREA_MASK (0x04 << 4) +#define FT6206_TOUCH_AREA_SHIFT 0x04 + +#define FT6206_P2_XH_REG 0x09 +#define FT6206_P2_XL_REG 0x0A +#define FT6206_P2_YH_REG 0x0B +#define FT6206_P2_YL_REG 0x0C +#define FT6206_P2_WEIGHT_REG 0x0D +#define FT6206_P2_MISC_REG 0x0E + + /* Threshold for touch detection */ +#define FT6206_TH_GROUP_REG 0x80 + + /* Values FT6206_TH_GROUP_REG : threshold related */ +#define FT6206_THRESHOLD_MASK 0xFF +#define FT6206_THRESHOLD_SHIFT 0 + + /* Filter function coefficients */ +#define FT6206_TH_DIFF_REG 0x85 + + /* Control register */ +#define FT6206_CTRL_REG 0x86 + + /* Values related to FT6206_CTRL_REG */ + + /* Will keep the Active mode when there is no touching */ +#define FT6206_CTRL_KEEP_ACTIVE_MODE 0x00 + + /* Switching from Active mode to Monitor mode automatically when there is no touching */ +#define FT6206_CTRL_KEEP_AUTO_SWITCH_MONITOR_MODE 0x01 + + /* The time period of switching from Active mode to Monitor mode when there is no touching */ +#define FT6206_TIMEENTERMONITOR_REG 0x87 + + /* Report rate in Active mode */ +#define FT6206_PERIODACTIVE_REG 0x88 + + /* Report rate in Monitor mode */ +#define FT6206_PERIODMONITOR_REG 0x89 + + /* The value of the minimum allowed angle while Rotating gesture mode */ +#define FT6206_RADIAN_VALUE_REG 0x91 + + /* Maximum offset while Moving Left and Moving Right gesture */ +#define FT6206_OFFSET_LEFT_RIGHT_REG 0x92 + + /* Maximum offset while Moving Up and Moving Down gesture */ +#define FT6206_OFFSET_UP_DOWN_REG 0x93 + + /* Minimum distance while Moving Left and Moving Right gesture */ +#define FT6206_DISTANCE_LEFT_RIGHT_REG 0x94 + + /* Minimum distance while Moving Up and Moving Down gesture */ +#define FT6206_DISTANCE_UP_DOWN_REG 0x95 + + /* Maximum distance while Zoom In and Zoom Out gesture */ +#define FT6206_DISTANCE_ZOOM_REG 0x96 + + /* High 8-bit of LIB Version info */ +#define FT6206_LIB_VER_H_REG 0xA1 + + /* Low 8-bit of LIB Version info */ +#define FT6206_LIB_VER_L_REG 0xA2 + + /* Chip Selecting */ +#define FT6206_CIPHER_REG 0xA3 + + /* Interrupt mode register (used when in interrupt mode) */ +#define FT6206_GMODE_REG 0xA4 + +#define FT6206_G_MODE_INTERRUPT_MASK 0x03 +#define FT6206_G_MODE_INTERRUPT_SHIFT 0x00 + + /* Possible values of FT6206_GMODE_REG */ +#define FT6206_G_MODE_INTERRUPT_POLLING 0x00 +#define FT6206_G_MODE_INTERRUPT_TRIGGER 0x01 + + /* Current power mode the FT6206 system is in (R) */ +#define FT6206_PWR_MODE_REG 0xA5 + + /* FT6206 firmware version */ +#define FT6206_FIRMID_REG 0xA6 + + /* FT6206 Chip identification register */ +#define FT6206_CHIP_ID_REG 0xA8 + + /* Possible values of FT6206_CHIP_ID_REG */ +#define FT6206_ID_VALUE 0x11 +#define FT6x36_ID_VALUE 0xCD + + /* Release code version */ +#define FT6206_RELEASE_CODE_ID_REG 0xAF + + /* Current operating mode the FT6206 system is in (R) */ +#define FT6206_STATE_REG 0xBC + + /** + * @} + */ + + /* Exported macro ------------------------------------------------------------*/ + + /** @defgroup ft6x06_Exported_Macros + * @{ + */ + + /* Exported functions --------------------------------------------------------*/ + + /** @defgroup ft6x06_Exported_Functions + * @{ + */ + + /** + * @brief ft6x06 Control functions + */ + + +/** + * @brief Initialize the ft6x06 communication bus + * from MCU to FT6206 : ie I2C channel initialization (if required). + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6206). + * @retval None + */ +void ft6x06_Init(uint16_t DeviceAddr); + +/** + * @brief Software Reset the ft6x06. + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6206). + * @retval None + */ +void ft6x06_Reset(uint16_t DeviceAddr); + +/** + * @brief Read the ft6x06 device ID, pre intitalize I2C in case of need to be + * able to read the FT6206 device ID, and verify this is a FT6206. + * @param DeviceAddr: I2C FT6x06 Slave address. + * @retval The Device ID (two bytes). + */ +uint16_t ft6x06_ReadID(uint16_t DeviceAddr); + +/** + * @brief Configures the touch Screen IC device to start detecting touches + * @param DeviceAddr: Device address on communication Bus (I2C slave address). + * @retval None. + */ +void ft6x06_TS_Start(uint16_t DeviceAddr); + +/** + * @brief Return if there is touches detected or not. + * Try to detect new touches and forget the old ones (reset internal global + * variables). + * @param DeviceAddr: Device address on communication Bus. + * @retval : Number of active touches detected (can be 0, 1 or 2). + */ +uint8_t ft6x06_TS_DetectTouch(uint16_t DeviceAddr); + +/** + * @brief Get the touch screen X and Y positions values + * Manage multi touch thanks to touch Index global + * variable 'ft6x06_handle.currActiveTouchIdx'. + * @param DeviceAddr: Device address on communication Bus. + * @param X: Pointer to X position value + * @param Y: Pointer to Y position value + * @retval None. + */ +void ft6x06_TS_GetXY(uint16_t DeviceAddr, uint16_t *X, uint16_t *Y); + +/** + * @brief Configure the FT6206 device to generate IT on given INT pin + * connected to MCU as EXTI. + * @param DeviceAddr: Device address on communication Bus (Slave I2C address of FT6206). + * @retval None + */ +void ft6x06_TS_EnableIT(uint16_t DeviceAddr); + +/** + * @brief Configure the FT6206 device to stop generating IT on the given INT pin + * connected to MCU as EXTI. + * @param DeviceAddr: Device address on communication Bus (Slave I2C address of FT6206). + * @retval None + */ +void ft6x06_TS_DisableIT(uint16_t DeviceAddr); + +/** + * @brief Get IT status from FT6206 interrupt status registers + * Should be called Following an EXTI coming to the MCU to know the detailed + * reason of the interrupt. + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6206). + * @retval TS interrupts status + */ +uint8_t ft6x06_TS_ITStatus (uint16_t DeviceAddr); + +/** + * @brief Clear IT status in FT6206 interrupt status clear registers + * Should be called Following an EXTI coming to the MCU. + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6206). + * @retval TS interrupts status + */ +void ft6x06_TS_ClearIT (uint16_t DeviceAddr); + +/**** NEW FEATURES enabled when Multi-touch support is enabled ****/ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + +/** + * @brief Get the last touch gesture identification (zoom, move up/down...). + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6x06). + * @param pGestureId : Pointer to get last touch gesture Identification. + * @retval None. + */ +void ft6x06_TS_GetGestureID(uint16_t DeviceAddr, uint32_t * pGestureId); + +/** + * @brief Get the touch detailed informations on touch number 'touchIdx' (0..1) + * This touch detailed information contains : + * - weight that was applied to this touch + * - sub-area of the touch in the touch panel + * - event of linked to the touch (press down, lift up, ...) + * @param DeviceAddr: Device address on communication Bus (I2C slave address of FT6x06). + * @param touchIdx : Passed index of the touch (0..1) on which we want to get the + * detailed information. + * @param pWeight : Pointer to to get the weight information of 'touchIdx'. + * @param pArea : Pointer to to get the sub-area information of 'touchIdx'. + * @param pEvent : Pointer to to get the event information of 'touchIdx'. + + * @retval None. + */ +void ft6x06_TS_GetTouchInfo(uint16_t DeviceAddr, + uint32_t touchIdx, + uint32_t * pWeight, + uint32_t * pArea, + uint32_t * pEvent); + +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +/* Imported TS IO functions --------------------------------------------------------*/ + +/** @defgroup ft6x06_Imported_Functions + * @{ + */ + +/* TouchScreen (TS) external IO functions */ +extern void TS_IO_Init(void); +extern void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +extern uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg); +extern uint16_t TS_IO_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); +extern void TS_IO_Delay(uint32_t Delay); + + /** + * @} + */ + + /* Imported global variables --------------------------------------------------------*/ + + /** @defgroup ft6x06_Imported_Globals + * @{ + */ + + +/* Touch screen driver structure */ +extern TS_DrvTypeDef ft6x06_ts_drv; + + /** + * @} + */ + +#ifdef __cplusplus +} +#endif +#endif /* __FT6X06_H */ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/mfxstm32l152/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/mfxstm32l152/Release_Notes.html new file mode 100644 index 00000000..ae8ec0e6 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/mfxstm32l152/Release_Notes.html @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + + + + Release Notes for MFXSTM32L152 Component Driver + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for MFXSTM32L152 Component Driver

+

Copyright +2015 STMicroelectronics

+

+
+

 

+ + + + + + +

Update History

V2.0.1 / 02-June-2017

Main Changes

  • Update comments to be used for PDSC generation

V2.0.0 / 24-June-2015

+ + + + + + + + + + + + + +

Main +Changes

  • Add Shunt management of MFXSTM32L152 component
    • new mfxstm32l152_IDD_ConfigShuntNbLimit() and mfxstm32l152_IDD_GetShuntUsed() APIs
  • Add mfxstm32l152_WriteReg() API
  • NOTE: This release must be used with BSP Common driver V4.0.0 or later

V1.2.0 / 28-April-2015

+ + + + + + + + + + + + + +

Main +Changes

    +
  • mfxstm32l152_IO_Config(): remove unnecessary delay
  • +
  • mfxstm32l152_TS_DetectTouch(): improve TouchScreen speed
  • +
  • mfxstm32l152_IDD_Config(): add configuration of number of measure to be performed, with delay between 2 measures
  • +
  • NOTE: This release must be used with BSP Common driver V3.0.0
  • +

V1.1.0 / 10-February-2015

+ + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • Low Power management of MFXSTM32L152 component:
    • New mfxstm32l152_DeInit() and mfxstm32l152_WakeUp() API
    • mfxstm32l152_LowPower() API completed to be MFXSTM32L152 in Standby mode
  • NOTE: This release must be used with BSP Common driver V2.2.0 or later

V1.0.0 / 05-February-2015

+ + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • First official release of MFXSTM32L152 IO Expander component driver.
  • NOTE: This release must be used with BSP Common driver V2.1.0 or later.

License

+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+ + + +
+
+
For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32
+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/mfxstm32l152/mfxstm32l152.c b/src/port_stm32f7/common/bsp_drivers/Components/mfxstm32l152/mfxstm32l152.c new file mode 100644 index 00000000..faadf68b --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/mfxstm32l152/mfxstm32l152.c @@ -0,0 +1,1602 @@ +/** + ****************************************************************************** + * @file mfxstm32l152.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the MFXSTM32L152 + * IO Expander devices. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "mfxstm32l152.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Component + * @{ + */ + +/** @defgroup MFXSTM32L152 + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ + +/** @defgroup MFXSTM32L152_Private_Types_Definitions + * @{ + */ + +/* Private define ------------------------------------------------------------*/ + +/** @defgroup MFXSTM32L152_Private_Defines + * @{ + */ +#define MFXSTM32L152_MAX_INSTANCE 3 + +/* Private macro -------------------------------------------------------------*/ + +/** @defgroup MFXSTM32L152_Private_Macros + * @{ + */ + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup MFXSTM32L152_Private_Variables + * @{ + */ + +/* Touch screen driver structure initialization */ +TS_DrvTypeDef mfxstm32l152_ts_drv = +{ + mfxstm32l152_Init, + mfxstm32l152_ReadID, + mfxstm32l152_Reset, + + mfxstm32l152_TS_Start, + mfxstm32l152_TS_DetectTouch, + mfxstm32l152_TS_GetXY, + + mfxstm32l152_TS_EnableIT, + mfxstm32l152_TS_ClearIT, + mfxstm32l152_TS_ITStatus, + mfxstm32l152_TS_DisableIT, +}; + +/* IO driver structure initialization */ +IO_DrvTypeDef mfxstm32l152_io_drv = +{ + mfxstm32l152_Init, + mfxstm32l152_ReadID, + mfxstm32l152_Reset, + + mfxstm32l152_IO_Start, + mfxstm32l152_IO_Config, + mfxstm32l152_IO_WritePin, + mfxstm32l152_IO_ReadPin, + + mfxstm32l152_IO_EnableIT, + mfxstm32l152_IO_DisableIT, + mfxstm32l152_IO_ITStatus, + mfxstm32l152_IO_ClearIT, +}; + +/* IDD driver structure initialization */ +IDD_DrvTypeDef mfxstm32l152_idd_drv = +{ + mfxstm32l152_Init, + mfxstm32l152_DeInit, + mfxstm32l152_ReadID, + mfxstm32l152_Reset, + mfxstm32l152_LowPower, + mfxstm32l152_WakeUp, + + mfxstm32l152_IDD_Start, + mfxstm32l152_IDD_Config, + mfxstm32l152_IDD_GetValue, + + mfxstm32l152_IDD_EnableIT, + mfxstm32l152_IDD_ClearIT, + mfxstm32l152_IDD_GetITStatus, + mfxstm32l152_IDD_DisableIT, + + mfxstm32l152_Error_EnableIT, + mfxstm32l152_Error_ClearIT, + mfxstm32l152_Error_GetITStatus, + mfxstm32l152_Error_DisableIT, + mfxstm32l152_Error_ReadSrc, + mfxstm32l152_Error_ReadMsg +}; + + +/* mfxstm32l152 instances by address */ +uint8_t mfxstm32l152[MFXSTM32L152_MAX_INSTANCE] = {0}; +/** + * @} + */ + +/* Private function prototypes -----------------------------------------------*/ + +/** @defgroup MFXSTM32L152_Private_Function_Prototypes + * @{ + */ +static uint8_t mfxstm32l152_GetInstance(uint16_t DeviceAddr); +static uint8_t mfxstm32l152_ReleaseInstance(uint16_t DeviceAddr); +static void mfxstm32l152_reg24_setPinValue(uint16_t DeviceAddr, uint8_t RegisterAddr, uint32_t PinPosition, uint8_t PinValue ); + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup MFXSTM32L152_Private_Functions + * @{ + */ + +/** + * @brief Initialize the mfxstm32l152 and configure the needed hardware resources + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_Init(uint16_t DeviceAddr) +{ + uint8_t instance; + uint8_t empty; + + /* Check if device instance already exists */ + instance = mfxstm32l152_GetInstance(DeviceAddr); + + /* To prevent double initialization */ + if(instance == 0xFF) + { + /* Look for empty instance */ + empty = mfxstm32l152_GetInstance(0); + + if(empty < MFXSTM32L152_MAX_INSTANCE) + { + /* Register the current device instance */ + mfxstm32l152[empty] = DeviceAddr; + + /* Initialize IO BUS layer */ + MFX_IO_Init(); + } + } + + mfxstm32l152_SetIrqOutPinPolarity(DeviceAddr, MFXSTM32L152_OUT_PIN_POLARITY_HIGH); + mfxstm32l152_SetIrqOutPinType(DeviceAddr, MFXSTM32L152_OUT_PIN_TYPE_PUSHPULL); +} + +/** + * @brief DeInitialize the mfxstm32l152 and unconfigure the needed hardware resources + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_DeInit(uint16_t DeviceAddr) +{ + uint8_t instance; + + /* release existing instance */ + instance = mfxstm32l152_ReleaseInstance(DeviceAddr); + + /* De-Init only if instance was previously registered */ + if(instance != 0xFF) + { + /* De-Initialize IO BUS layer */ + MFX_IO_DeInit(); + } +} + +/** + * @brief Reset the mfxstm32l152 by Software. + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_Reset(uint16_t DeviceAddr) +{ + /* Soft Reset */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_SYS_CTRL, MFXSTM32L152_SWRST); + + /* Wait for a delay to ensure registers erasing */ + MFX_IO_Delay(10); +} + +/** + * @brief Put mfxstm32l152 Device in Low Power standby mode + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_LowPower(uint16_t DeviceAddr) +{ + /* Enter standby mode */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_SYS_CTRL, MFXSTM32L152_STANDBY); + + /* enable wakeup pin */ + MFX_IO_EnableWakeupPin(); +} + +/** + * @brief WakeUp mfxstm32l152 from standby mode + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_WakeUp(uint16_t DeviceAddr) +{ + uint8_t instance; + + /* Check if device instance already exists */ + instance = mfxstm32l152_GetInstance(DeviceAddr); + + /* if instance does not exist, first initialize pins*/ + if(instance == 0xFF) + { + /* enable wakeup pin */ + MFX_IO_EnableWakeupPin(); + } + + /* toggle wakeup pin */ + MFX_IO_Wakeup(); +} + +/** + * @brief Read the MFXSTM32L152 IO Expander device ID. + * @param DeviceAddr: Device address on communication Bus. + * @retval The Device ID (two bytes). + */ +uint16_t mfxstm32l152_ReadID(uint16_t DeviceAddr) +{ + uint8_t id; + + /* Wait for a delay to ensure the state of registers */ + MFX_IO_Delay(1); + + /* Initialize IO BUS layer */ + MFX_IO_Init(); + + id = MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_ID); + + /* Return the device ID value */ + return (id); +} + +/** + * @brief Read the MFXSTM32L152 device firmware version. + * @param DeviceAddr: Device address on communication Bus. + * @retval The Device FW version (two bytes). + */ +uint16_t mfxstm32l152_ReadFwVersion(uint16_t DeviceAddr) +{ + uint8_t data[2]; + + MFX_IO_ReadMultiple((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_FW_VERSION_MSB, data, sizeof(data)) ; + + /* Recompose MFX firmware value */ + return ((data[0] << 8) | data[1]); +} + +/** + * @brief Enable the interrupt mode for the selected IT source + * @param DeviceAddr: Device address on communication Bus. + * @param Source: The interrupt source to be configured, could be: + * @arg MFXSTM32L152_IRQ_GPIO: IO interrupt + * @arg MFXSTM32L152_IRQ_IDD : IDD interrupt + * @arg MFXSTM32L152_IRQ_ERROR : Error interrupt + * @arg MFXSTM32L152_IRQ_TS_DET : Touch Screen Controller Touch Detected interrupt + * @arg MFXSTM32L152_IRQ_TS_NE : Touch Screen FIFO Not Empty + * @arg MFXSTM32L152_IRQ_TS_TH : Touch Screen FIFO threshold triggered + * @arg MFXSTM32L152_IRQ_TS_FULL : Touch Screen FIFO Full + * @arg MFXSTM32L152_IRQ_TS_OVF : Touch Screen FIFO Overflow + * @retval None + */ +void mfxstm32l152_EnableITSource(uint16_t DeviceAddr, uint8_t Source) +{ + uint8_t tmp = 0; + + /* Get the current value of the INT_EN register */ + tmp = MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_SRC_EN); + + /* Set the interrupts to be Enabled */ + tmp |= Source; + + /* Set the register */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_SRC_EN, tmp); +} + +/** + * @brief Disable the interrupt mode for the selected IT source + * @param DeviceAddr: Device address on communication Bus. + * @param Source: The interrupt source to be configured, could be: + * @arg MFXSTM32L152_IRQ_GPIO: IO interrupt + * @arg MFXSTM32L152_IRQ_IDD : IDD interrupt + * @arg MFXSTM32L152_IRQ_ERROR : Error interrupt + * @arg MFXSTM32L152_IRQ_TS_DET : Touch Screen Controller Touch Detected interrupt + * @arg MFXSTM32L152_IRQ_TS_NE : Touch Screen FIFO Not Empty + * @arg MFXSTM32L152_IRQ_TS_TH : Touch Screen FIFO threshold triggered + * @arg MFXSTM32L152_IRQ_TS_FULL : Touch Screen FIFO Full + * @arg MFXSTM32L152_IRQ_TS_OVF : Touch Screen FIFO Overflow + * @retval None + */ +void mfxstm32l152_DisableITSource(uint16_t DeviceAddr, uint8_t Source) +{ + uint8_t tmp = 0; + + /* Get the current value of the INT_EN register */ + tmp = MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_SRC_EN); + + /* Set the interrupts to be Enabled */ + tmp &= ~Source; + + /* Set the register */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_SRC_EN, tmp); +} + + +/** + * @brief Returns the selected Global interrupt source pending bit value + * @param DeviceAddr: Device address on communication Bus. + * @param Source: the Global interrupt source to be checked, could be: + * @arg MFXSTM32L152_IRQ_GPIO: IO interrupt + * @arg MFXSTM32L152_IRQ_IDD : IDD interrupt + * @arg MFXSTM32L152_IRQ_ERROR : Error interrupt + * @arg MFXSTM32L152_IRQ_TS_DET : Touch Screen Controller Touch Detected interrupt + * @arg MFXSTM32L152_IRQ_TS_NE : Touch Screen FIFO Not Empty + * @arg MFXSTM32L152_IRQ_TS_TH : Touch Screen FIFO threshold triggered + * @arg MFXSTM32L152_IRQ_TS_FULL : Touch Screen FIFO Full + * @arg MFXSTM32L152_IRQ_TS_OVF : Touch Screen FIFO Overflow + * @retval The value of the checked Global interrupt source status. + */ +uint8_t mfxstm32l152_GlobalITStatus(uint16_t DeviceAddr, uint8_t Source) +{ + /* Return the global IT source status (pending or not)*/ + return((MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_PENDING) & Source)); +} + +/** + * @brief Clear the selected Global interrupt pending bit(s) + * @param DeviceAddr: Device address on communication Bus. + * @param Source: the Global interrupt source to be cleared, could be any combination + * of the below values. The acknowledge signal for MFXSTM32L152_GPIOs configured in input + * with interrupt is not on this register but in IRQ_GPI_ACK1, IRQ_GPI_ACK2 registers. + * @arg MFXSTM32L152_IRQ_IDD : IDD interrupt + * @arg MFXSTM32L152_IRQ_ERROR : Error interrupt + * @arg MFXSTM32L152_IRQ_TS_DET : Touch Screen Controller Touch Detected interrupt + * @arg MFXSTM32L152_IRQ_TS_NE : Touch Screen FIFO Not Empty + * @arg MFXSTM32L152_IRQ_TS_TH : Touch Screen FIFO threshold triggered + * @arg MFXSTM32L152_IRQ_TS_FULL : Touch Screen FIFO Full + * @arg MFXSTM32L152_IRQ_TS_OVF : Touch Screen FIFO Overflow + * /\/\ IMPORTANT NOTE /\/\ must not use MFXSTM32L152_IRQ_GPIO as argument, see IRQ_GPI_ACK1 and IRQ_GPI_ACK2 registers + * @retval None + */ +void mfxstm32l152_ClearGlobalIT(uint16_t DeviceAddr, uint8_t Source) +{ + /* Write 1 to the bits that have to be cleared */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_ACK, Source); +} + +/** + * @brief Set the global interrupt Polarity of IRQ_OUT_PIN. + * @param DeviceAddr: Device address on communication Bus. + * @param Polarity: the IT mode polarity, could be one of the following values: + * @arg MFXSTM32L152_OUT_PIN_POLARITY_LOW: Interrupt output line is active Low edge + * @arg MFXSTM32L152_OUT_PIN_POLARITY_HIGH: Interrupt line output is active High edge + * @retval None + */ +void mfxstm32l152_SetIrqOutPinPolarity(uint16_t DeviceAddr, uint8_t Polarity) +{ + uint8_t tmp = 0; + + /* Get the current register value */ + tmp = MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_MFX_IRQ_OUT); + + /* Mask the polarity bits */ + tmp &= ~(uint8_t)0x02; + + /* Modify the Interrupt Output line configuration */ + tmp |= Polarity; + + /* Set the new register value */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_MFX_IRQ_OUT, tmp); + + /* Wait for 1 ms for MFX to change IRQ_out pin config, before activate it */ + MFX_IO_Delay(1); + +} + +/** + * @brief Set the global interrupt Type of IRQ_OUT_PIN. + * @param DeviceAddr: Device address on communication Bus. + * @param Type: Interrupt line activity type, could be one of the following values: + * @arg MFXSTM32L152_OUT_PIN_TYPE_OPENDRAIN: Open Drain output Interrupt line + * @arg MFXSTM32L152_OUT_PIN_TYPE_PUSHPULL: Push Pull output Interrupt line + * @retval None + */ +void mfxstm32l152_SetIrqOutPinType(uint16_t DeviceAddr, uint8_t Type) +{ + uint8_t tmp = 0; + + /* Get the current register value */ + tmp = MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_MFX_IRQ_OUT); + + /* Mask the type bits */ + tmp &= ~(uint8_t)0x01; + + /* Modify the Interrupt Output line configuration */ + tmp |= Type; + + /* Set the new register value */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_MFX_IRQ_OUT, tmp); + + /* Wait for 1 ms for MFX to change IRQ_out pin config, before activate it */ + MFX_IO_Delay(1); + +} + + +/* ------------------------------------------------------------------ */ +/* ----------------------- GPIO ------------------------------------- */ +/* ------------------------------------------------------------------ */ + + +/** + * @brief Start the IO functionality used and enable the AF for selected IO pin(s). + * @param DeviceAddr: Device address on communication Bus. + * @param AF_en: 0 to disable, else enabled. + * @retval None + */ +void mfxstm32l152_IO_Start(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + uint8_t mode; + + /* Get the current register value */ + mode = MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_SYS_CTRL); + + /* Set the IO Functionalities to be Enabled */ + mode |= MFXSTM32L152_GPIO_EN; + + /* Enable ALTERNATE functions */ + /* AGPIO[0..3] can be either IDD or GPIO */ + /* AGPIO[4..7] can be either TS or GPIO */ + /* if IDD or TS are enabled no matter the value this bit GPIO are not available for those pins */ + /* however the MFX will waste some cycles to to handle these potential GPIO (pooling, etc) */ + /* so if IDD and TS are both active it is better to let ALTERNATE off (0) */ + /* if however IDD or TS are not connected then set it on gives more GPIOs availability */ + /* remind that AGPIO are less efficient then normal GPIO (They use pooling rather then EXTI */ + if (IO_Pin > 0xFFFF) + { + mode |= MFXSTM32L152_ALTERNATE_GPIO_EN; + } + else + { + mode &= ~MFXSTM32L152_ALTERNATE_GPIO_EN; + } + + /* Write the new register value */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_SYS_CTRL, mode); + + /* Wait for 1 ms for MFX to change IRQ_out pin config, before activate it */ + MFX_IO_Delay(1); +} + +/** + * @brief Configures the IO pin(s) according to IO mode structure value. + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The output pin to be set or reset. This parameter can be one + * of the following values: + * @arg MFXSTM32L152_GPIO_PIN_x: where x can be from 0 to 23. + * @param IO_Mode: The IO pin mode to configure, could be one of the following values: + * @arg IO_MODE_INPUT + * @arg IO_MODE_OUTPUT + * @arg IO_MODE_IT_RISING_EDGE + * @arg IO_MODE_IT_FALLING_EDGE + * @arg IO_MODE_IT_LOW_LEVEL + * @arg IO_MODE_IT_HIGH_LEVEL + * @arg IO_MODE_INPUT_PU, + * @arg IO_MODE_INPUT_PD, + * @arg IO_MODE_OUTPUT_OD_PU, + * @arg IO_MODE_OUTPUT_OD_PD, + * @arg IO_MODE_OUTPUT_PP_PU, + * @arg IO_MODE_OUTPUT_PP_PD, + * @arg IO_MODE_IT_RISING_EDGE_PU + * @arg IO_MODE_IT_FALLING_EDGE_PU + * @arg IO_MODE_IT_LOW_LEVEL_PU + * @arg IO_MODE_IT_HIGH_LEVEL_PU + * @arg IO_MODE_IT_RISING_EDGE_PD + * @arg IO_MODE_IT_FALLING_EDGE_PD + * @arg IO_MODE_IT_LOW_LEVEL_PD + * @arg IO_MODE_IT_HIGH_LEVEL_PD + * @retval None + */ +uint8_t mfxstm32l152_IO_Config(uint16_t DeviceAddr, uint32_t IO_Pin, IO_ModeTypedef IO_Mode) +{ + uint8_t error_code = 0; + + /* Configure IO pin according to selected IO mode */ + switch(IO_Mode) + { + case IO_MODE_OFF: /* Off or analog mode */ + case IO_MODE_ANALOG: /* Off or analog mode */ + mfxstm32l152_IO_DisablePinIT(DeviceAddr, IO_Pin); /* first disable IT */ + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITHOUT_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_DOWN); + break; + + case IO_MODE_INPUT: /* Input mode */ + mfxstm32l152_IO_DisablePinIT(DeviceAddr, IO_Pin); /* first disable IT */ + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITHOUT_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_UP); + break; + + case IO_MODE_INPUT_PU: /* Input mode */ + mfxstm32l152_IO_DisablePinIT(DeviceAddr, IO_Pin); /* first disable IT */ + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITH_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_UP); + break; + + case IO_MODE_INPUT_PD: /* Input mode */ + mfxstm32l152_IO_DisablePinIT(DeviceAddr, IO_Pin); /* first disable IT */ + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITH_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_DOWN); + break; + + case IO_MODE_OUTPUT: /* Output mode */ + case IO_MODE_OUTPUT_PP_PD: /* Output mode */ + mfxstm32l152_IO_DisablePinIT(DeviceAddr, IO_Pin); /* first disable IT */ + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_OUT); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPO_PUSH_PULL); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_DOWN); + break; + + case IO_MODE_OUTPUT_PP_PU: /* Output mode */ + mfxstm32l152_IO_DisablePinIT(DeviceAddr, IO_Pin); /* first disable IT */ + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_OUT); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPO_PUSH_PULL); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_UP); + break; + + case IO_MODE_OUTPUT_OD_PD: /* Output mode */ + mfxstm32l152_IO_DisablePinIT(DeviceAddr, IO_Pin); /* first disable IT */ + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_OUT); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPO_OPEN_DRAIN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_DOWN); + break; + + case IO_MODE_OUTPUT_OD_PU: /* Output mode */ + mfxstm32l152_IO_DisablePinIT(DeviceAddr, IO_Pin); /* first disable IT */ + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_OUT); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPO_OPEN_DRAIN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_UP); + break; + + case IO_MODE_IT_RISING_EDGE: /* Interrupt rising edge mode */ + mfxstm32l152_IO_EnableIT(DeviceAddr); + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITHOUT_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_UP); + mfxstm32l152_IO_SetIrqEvtMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_EVT_EDGE); + mfxstm32l152_IO_SetIrqTypeMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_TYPE_HLRE); + mfxstm32l152_IO_EnablePinIT(DeviceAddr, IO_Pin); /* last to do: enable IT */ + break; + + case IO_MODE_IT_RISING_EDGE_PU: /* Interrupt rising edge mode */ + mfxstm32l152_IO_EnableIT(DeviceAddr); + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITH_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_UP); + mfxstm32l152_IO_SetIrqEvtMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_EVT_EDGE); + mfxstm32l152_IO_SetIrqTypeMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_TYPE_HLRE); + mfxstm32l152_IO_EnablePinIT(DeviceAddr, IO_Pin); /* last to do: enable IT */ + break; + + case IO_MODE_IT_RISING_EDGE_PD: /* Interrupt rising edge mode */ + mfxstm32l152_IO_EnableIT(DeviceAddr); + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITH_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_DOWN); + mfxstm32l152_IO_SetIrqEvtMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_EVT_EDGE); + mfxstm32l152_IO_SetIrqTypeMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_TYPE_HLRE); + mfxstm32l152_IO_EnablePinIT(DeviceAddr, IO_Pin); /* last to do: enable IT */ + break; + + case IO_MODE_IT_FALLING_EDGE: /* Interrupt falling edge mode */ + mfxstm32l152_IO_EnableIT(DeviceAddr); + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITHOUT_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_UP); + mfxstm32l152_IO_SetIrqEvtMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_EVT_EDGE); + mfxstm32l152_IO_SetIrqTypeMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_TYPE_LLFE); + mfxstm32l152_IO_EnablePinIT(DeviceAddr, IO_Pin); /* last to do: enable IT */ + break; + + case IO_MODE_IT_FALLING_EDGE_PU: /* Interrupt falling edge mode */ + mfxstm32l152_IO_EnableIT(DeviceAddr); + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITH_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_UP); + mfxstm32l152_IO_SetIrqEvtMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_EVT_EDGE); + mfxstm32l152_IO_SetIrqTypeMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_TYPE_LLFE); + mfxstm32l152_IO_EnablePinIT(DeviceAddr, IO_Pin); /* last to do: enable IT */ + break; + + case IO_MODE_IT_FALLING_EDGE_PD: /* Interrupt falling edge mode */ + mfxstm32l152_IO_EnableIT(DeviceAddr); + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITH_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_DOWN); + mfxstm32l152_IO_SetIrqEvtMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_EVT_EDGE); + mfxstm32l152_IO_SetIrqTypeMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_TYPE_LLFE); + mfxstm32l152_IO_EnablePinIT(DeviceAddr, IO_Pin); /* last to do: enable IT */ + break; + + case IO_MODE_IT_LOW_LEVEL: /* Low level interrupt mode */ + mfxstm32l152_IO_EnableIT(DeviceAddr); + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITHOUT_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_UP); + mfxstm32l152_IO_SetIrqEvtMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_EVT_LEVEL); + mfxstm32l152_IO_SetIrqTypeMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_TYPE_LLFE); + mfxstm32l152_IO_EnablePinIT(DeviceAddr, IO_Pin); /* last to do: enable IT */ + break; + + case IO_MODE_IT_LOW_LEVEL_PU: /* Low level interrupt mode */ + mfxstm32l152_IO_EnableIT(DeviceAddr); + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITH_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_UP); + mfxstm32l152_IO_SetIrqEvtMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_EVT_LEVEL); + mfxstm32l152_IO_SetIrqTypeMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_TYPE_LLFE); + mfxstm32l152_IO_EnablePinIT(DeviceAddr, IO_Pin); /* last to do: enable IT */ + break; + + case IO_MODE_IT_LOW_LEVEL_PD: /* Low level interrupt mode */ + mfxstm32l152_IO_EnableIT(DeviceAddr); + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITH_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_DOWN); + mfxstm32l152_IO_SetIrqEvtMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_EVT_LEVEL); + mfxstm32l152_IO_SetIrqTypeMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_TYPE_LLFE); + mfxstm32l152_IO_EnablePinIT(DeviceAddr, IO_Pin); /* last to do: enable IT */ + break; + + case IO_MODE_IT_HIGH_LEVEL: /* High level interrupt mode */ + mfxstm32l152_IO_EnableIT(DeviceAddr); + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITHOUT_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_UP); + mfxstm32l152_IO_SetIrqEvtMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_EVT_LEVEL); + mfxstm32l152_IO_SetIrqTypeMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_TYPE_HLRE); + mfxstm32l152_IO_EnablePinIT(DeviceAddr, IO_Pin); /* last to do: enable IT */ + break; + + case IO_MODE_IT_HIGH_LEVEL_PU: /* High level interrupt mode */ + mfxstm32l152_IO_EnableIT(DeviceAddr); + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITH_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_UP); + mfxstm32l152_IO_SetIrqEvtMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_EVT_LEVEL); + mfxstm32l152_IO_SetIrqTypeMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_TYPE_HLRE); + mfxstm32l152_IO_EnablePinIT(DeviceAddr, IO_Pin); /* last to do: enable IT */ + break; + + case IO_MODE_IT_HIGH_LEVEL_PD: /* High level interrupt mode */ + mfxstm32l152_IO_EnableIT(DeviceAddr); + mfxstm32l152_IO_InitPin(DeviceAddr, IO_Pin, MFXSTM32L152_GPIO_DIR_IN); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_TYPE1, IO_Pin, MFXSTM32L152_GPI_WITH_PULL_RESISTOR); + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_PUPD1, IO_Pin, MFXSTM32L152_GPIO_PULL_DOWN); + mfxstm32l152_IO_SetIrqEvtMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_EVT_LEVEL); + mfxstm32l152_IO_SetIrqTypeMode(DeviceAddr, IO_Pin, MFXSTM32L152_IRQ_GPI_TYPE_HLRE); + mfxstm32l152_IO_EnablePinIT(DeviceAddr, IO_Pin); /* last to do: enable IT */ + break; + + default: + error_code = (uint8_t) IO_Mode; + break; + } + + return error_code; +} + +/** + * @brief Initialize the selected IO pin direction. + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO pin to be configured. This parameter could be any + * combination of the following values: + * @arg MFXSTM32L152_GPIO_PIN_x: Where x can be from 0 to 23. + * @param Direction: could be MFXSTM32L152_GPIO_DIR_IN or MFXSTM32L152_GPIO_DIR_OUT. + * @retval None + */ +void mfxstm32l152_IO_InitPin(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t Direction) +{ + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_DIR1, IO_Pin, Direction); +} + +/** + * @brief Set the global interrupt Type. + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO pin to be configured. This parameter could be any + * combination of the following values: + * @arg MFXSTM32L152_GPIO_PIN_x: Where x can be from 0 to 23. + * @param Evt: Interrupt line activity type, could be one of the following values: + * @arg MFXSTM32L152_IRQ_GPI_EVT_LEVEL: Interrupt line is active in level model + * @arg MFXSTM32L152_IRQ_GPI_EVT_EDGE: Interrupt line is active in edge model + * @retval None + */ +void mfxstm32l152_IO_SetIrqEvtMode(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t Evt) +{ + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_GPI_EVT1, IO_Pin, Evt); + MFX_IO_Delay(1); +} + +/** + * @brief Configure the Edge for which a transition is detectable for the + * selected pin. + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO pin to be configured. This parameter could be any + * combination of the following values: + * @arg MFXSTM32L152_GPIO_PIN_x: Where x can be from 0 to 23. + * @param Evt: Interrupt line activity type, could be one of the following values: + * @arg MFXSTM32L152_IRQ_GPI_TYPE_LLFE: Interrupt line is active in Low Level or Falling Edge + * @arg MFXSTM32L152_IRQ_GPI_TYPE_HLRE: Interrupt line is active in High Level or Rising Edge + * @retval None + */ +void mfxstm32l152_IO_SetIrqTypeMode(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t Type) +{ + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_GPI_TYPE1, IO_Pin, Type); + MFX_IO_Delay(1); +} + +/** + * @brief When GPIO is in output mode, puts the corresponding GPO in High (1) or Low (0) level. + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The output pin to be set or reset. This parameter can be one + * of the following values: + * @arg MFXSTM32L152_GPIO_PIN_x: where x can be from 0 to 23. + * @param PinState: The new IO pin state. + * @retval None + */ +void mfxstm32l152_IO_WritePin(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t PinState) +{ + /* Apply the bit value to the selected pin */ + if (PinState != 0) + { + /* Set the SET register */ + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPO_SET1, IO_Pin, 1); + } + else + { + /* Set the CLEAR register */ + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_GPO_CLR1, IO_Pin, 1); + } +} + +/** + * @brief Return the state of the selected IO pin(s). + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The output pin to be set or reset. This parameter can be one + * of the following values: + * @arg MFXSTM32L152_GPIO_PIN_x: where x can be from 0 to 23. + * @retval IO pin(s) state. + */ +uint32_t mfxstm32l152_IO_ReadPin(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + uint32_t tmp1 = 0; + uint32_t tmp2 = 0; + uint32_t tmp3 = 0; + + if(IO_Pin & 0x000000FF) + { + tmp1 = (uint32_t) MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_STATE1); + } + if(IO_Pin & 0x0000FF00) + { + tmp2 = (uint32_t) MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_STATE2); + } + if(IO_Pin & 0x00FF0000) + { + tmp3 = (uint32_t) MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_GPIO_STATE3); + } + + tmp3 = tmp1 + (tmp2 << 8) + (tmp3 << 16); + + return(tmp3 & IO_Pin); +} + +/** + * @brief Enable the global IO interrupt source. + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_IO_EnableIT(uint16_t DeviceAddr) +{ + MFX_IO_ITConfig(); + + /* Enable global IO IT source */ + mfxstm32l152_EnableITSource(DeviceAddr, MFXSTM32L152_IRQ_GPIO); +} + +/** + * @brief Disable the global IO interrupt source. + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_IO_DisableIT(uint16_t DeviceAddr) +{ + /* Disable global IO IT source */ + mfxstm32l152_DisableITSource(DeviceAddr, MFXSTM32L152_IRQ_GPIO); +} + +/** + * @brief Enable interrupt mode for the selected IO pin(s). + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO interrupt to be enabled. This parameter could be any + * combination of the following values: + * @arg MFXSTM32L152_GPIO_PIN_x: where x can be from 0 to 23. + * @retval None + */ +void mfxstm32l152_IO_EnablePinIT(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_GPI_SRC1, IO_Pin, 1); +} + +/** + * @brief Disable interrupt mode for the selected IO pin(s). + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO interrupt to be disabled. This parameter could be any + * combination of the following values: + * @arg MFXSTM32L152_GPIO_PIN_x: where x can be from 0 to 23. + * @retval None + */ +void mfxstm32l152_IO_DisablePinIT(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + mfxstm32l152_reg24_setPinValue(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_GPI_SRC1, IO_Pin, 0); +} + + +/** + * @brief Check the status of the selected IO interrupt pending bit + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO interrupt to be checked could be: + * @arg MFXSTM32L152_GPIO_PIN_x Where x can be from 0 to 23. + * @retval Status of the checked IO pin(s). + */ +uint32_t mfxstm32l152_IO_ITStatus(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + /* Get the Interrupt status */ + uint8_t tmp1 = 0; + uint16_t tmp2 = 0; + uint32_t tmp3 = 0; + + if(IO_Pin & 0xFF) + { + tmp1 = MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_GPI_PENDING1); + } + if(IO_Pin & 0xFFFF00) + { + tmp2 = (uint16_t) MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_GPI_PENDING2); + } + if(IO_Pin & 0xFFFF0000) + { + tmp3 = (uint32_t) MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_GPI_PENDING3); + } + + tmp3 = tmp1 + (tmp2 << 8) + (tmp3 << 16); + + return(tmp3 & IO_Pin); +} + +/** + * @brief Clear the selected IO interrupt pending bit(s). It clear automatically also the general MFXSTM32L152_REG_ADR_IRQ_PENDING + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: the IO interrupt to be cleared, could be: + * @arg MFXSTM32L152_GPIO_PIN_x: Where x can be from 0 to 23. + * @retval None + */ +void mfxstm32l152_IO_ClearIT(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + /* Clear the IO IT pending bit(s) by acknowledging */ + /* it cleans automatically also the Global IRQ_GPIO */ + /* normally this function is called under interrupt */ + uint8_t pin_0_7, pin_8_15, pin_16_23; + + pin_0_7 = IO_Pin & 0x0000ff; + pin_8_15 = IO_Pin >> 8; + pin_8_15 = pin_8_15 & 0x00ff; + pin_16_23 = IO_Pin >> 16; + + if (pin_0_7) + { + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_GPI_ACK1, pin_0_7); + } + if (pin_8_15) + { + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_GPI_ACK2, pin_8_15); + } + if (pin_16_23) + { + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_IRQ_GPI_ACK3, pin_16_23); + } +} + + +/** + * @brief Enable the AF for aGPIO. + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_IO_EnableAF(uint16_t DeviceAddr) +{ + uint8_t mode; + + /* Get the current register value */ + mode = MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_SYS_CTRL); + + /* Enable ALTERNATE functions */ + /* AGPIO[0..3] can be either IDD or GPIO */ + /* AGPIO[4..7] can be either TS or GPIO */ + /* if IDD or TS are enabled no matter the value this bit GPIO are not available for those pins */ + /* however the MFX will waste some cycles to to handle these potential GPIO (pooling, etc) */ + /* so if IDD and TS are both active it is better to let ALTERNATE disabled (0) */ + /* if however IDD or TS are not connected then set it on gives more GPIOs availability */ + /* remind that AGPIO are less efficient then normal GPIO (they use pooling rather then EXTI) */ + mode |= MFXSTM32L152_ALTERNATE_GPIO_EN; + + /* Write the new register value */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_SYS_CTRL, mode); +} + +/** + * @brief Disable the AF for aGPIO. + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ + void mfxstm32l152_IO_DisableAF(uint16_t DeviceAddr) +{ + uint8_t mode; + + /* Get the current register value */ + mode = MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_SYS_CTRL); + + /* Enable ALTERNATE functions */ + /* AGPIO[0..3] can be either IDD or GPIO */ + /* AGPIO[4..7] can be either TS or GPIO */ + /* if IDD or TS are enabled no matter the value this bit GPIO are not available for those pins */ + /* however the MFX will waste some cycles to to handle these potential GPIO (pooling, etc) */ + /* so if IDD and TS are both active it is better to let ALTERNATE disabled (0) */ + /* if however IDD or TS are not connected then set it on gives more GPIOs availability */ + /* remind that AGPIO are less efficient then normal GPIO (they use pooling rather then EXTI) */ + mode &= ~MFXSTM32L152_ALTERNATE_GPIO_EN; + + /* Write the new register value */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_SYS_CTRL, mode); + +} + + +/* ------------------------------------------------------------------ */ +/* --------------------- TOUCH SCREEN ------------------------------- */ +/* ------------------------------------------------------------------ */ + +/** + * @brief Configures the touch Screen Controller (Single point detection) + * @param DeviceAddr: Device address on communication Bus. + * @retval None. + */ +void mfxstm32l152_TS_Start(uint16_t DeviceAddr) +{ + uint8_t mode; + + /* Get the current register value */ + mode = MFX_IO_Read(DeviceAddr, MFXSTM32L152_REG_ADR_SYS_CTRL); + + /* Set the Functionalities to be Enabled */ + mode |= MFXSTM32L152_TS_EN; + + /* Set the new register value */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_REG_ADR_SYS_CTRL, mode); + + /* Wait for 2 ms */ + MFX_IO_Delay(2); + + /* Select 2 nF filter capacitor */ + /* Configuration: + - Touch average control : 4 samples + - Touch delay time : 500 uS + - Panel driver setting time: 500 uS + */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_TS_SETTLING, 0x32); + MFX_IO_Write(DeviceAddr, MFXSTM32L152_TS_TOUCH_DET_DELAY, 0x5); + MFX_IO_Write(DeviceAddr, MFXSTM32L152_TS_AVE, 0x04); + + /* Configure the Touch FIFO threshold: single point reading */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_TS_FIFO_TH, 0x01); + + /* Clear the FIFO memory content. */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_TS_FIFO_TH, MFXSTM32L152_TS_CLEAR_FIFO); + + /* Touch screen control configuration : + - No window tracking index + */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_TS_TRACK, 0x00); + + + /* Clear all the IT status pending bits if any */ + mfxstm32l152_IO_ClearIT(DeviceAddr, 0xFFFFFF); + + /* Wait for 1 ms delay */ + MFX_IO_Delay(1); +} + +/** + * @brief Return if there is touch detected or not. + * @param DeviceAddr: Device address on communication Bus. + * @retval Touch detected state. + */ +uint8_t mfxstm32l152_TS_DetectTouch(uint16_t DeviceAddr) +{ + uint8_t state; + uint8_t ret = 0; + + state = MFX_IO_Read(DeviceAddr, MFXSTM32L152_TS_FIFO_STA); + state = ((state & (uint8_t)MFXSTM32L152_TS_CTRL_STATUS) == (uint8_t)MFXSTM32L152_TS_CTRL_STATUS); + + if(state > 0) + { + if(MFX_IO_Read(DeviceAddr, MFXSTM32L152_TS_FIFO_LEVEL) > 0) + { + ret = 1; + } + } + + return ret; +} + +/** + * @brief Get the touch screen X and Y positions values + * @param DeviceAddr: Device address on communication Bus. + * @param X: Pointer to X position value + * @param Y: Pointer to Y position value + * @retval None. + */ +void mfxstm32l152_TS_GetXY(uint16_t DeviceAddr, uint16_t *X, uint16_t *Y) +{ + uint8_t data_xy[3]; + + MFX_IO_ReadMultiple(DeviceAddr, MFXSTM32L152_TS_XY_DATA, data_xy, sizeof(data_xy)) ; + + /* Calculate positions values */ + *X = (data_xy[1]<<4) + (data_xy[0]>>4); + *Y = (data_xy[2]<<4) + (data_xy[0]&4); + + /* Reset the FIFO memory content. */ + MFX_IO_Write(DeviceAddr, MFXSTM32L152_TS_FIFO_TH, MFXSTM32L152_TS_CLEAR_FIFO); +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_TS_EnableIT(uint16_t DeviceAddr) +{ + MFX_IO_ITConfig(); + + /* Enable global TS IT source */ + mfxstm32l152_EnableITSource(DeviceAddr, MFXSTM32L152_IRQ_TS_DET); +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_TS_DisableIT(uint16_t DeviceAddr) +{ + /* Disable global TS IT source */ + mfxstm32l152_DisableITSource(DeviceAddr, MFXSTM32L152_IRQ_TS_DET); +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval TS interrupts status + */ +uint8_t mfxstm32l152_TS_ITStatus(uint16_t DeviceAddr) +{ + /* Return TS interrupts status */ + return(mfxstm32l152_GlobalITStatus(DeviceAddr, MFXSTM32L152_IRQ_TS)); +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_TS_ClearIT(uint16_t DeviceAddr) +{ + /* Clear the global TS IT source */ + mfxstm32l152_ClearGlobalIT(DeviceAddr, MFXSTM32L152_IRQ_TS); +} + +/* ------------------------------------------------------------------ */ +/* --------------------- IDD MEASUREMENT ---------------------------- */ +/* ------------------------------------------------------------------ */ + +/** + * @brief Launch IDD current measurement + * @param DeviceAddr: Device address on communication Bus + * @retval None. + */ +void mfxstm32l152_IDD_Start(uint16_t DeviceAddr) +{ + uint8_t mode = 0; + + /* Get the current register value */ + mode = MFX_IO_Read((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_CTRL); + + /* Set the Functionalities to be enabled */ + mode |= MFXSTM32L152_IDD_CTRL_REQ; + + /* Start measurement campaign */ + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_CTRL, mode); +} + +/** + * @brief Configures the IDD current measurement + * @param DeviceAddr: Device address on communication Bus. + * @param MfxIddConfig: Parameters depending on hardware config. + * @retval None + */ +void mfxstm32l152_IDD_Config(uint16_t DeviceAddr, IDD_ConfigTypeDef MfxIddConfig) +{ + uint8_t value = 0; + uint8_t mode = 0; + + /* Get the current register value */ + mode = MFX_IO_Read((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_SYS_CTRL); + + if((mode & MFXSTM32L152_IDD_EN) != MFXSTM32L152_IDD_EN) + { + /* Set the Functionalities to be enabled */ + mode |= MFXSTM32L152_IDD_EN; + + /* Set the new register value */ + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_SYS_CTRL, mode); + } + + /* Control register setting: number of shunts */ + value = ((MfxIddConfig.ShuntNbUsed << 1) & MFXSTM32L152_IDD_CTRL_SHUNT_NB); + value |= (MfxIddConfig.VrefMeasurement & MFXSTM32L152_IDD_CTRL_VREF_DIS); + value |= (MfxIddConfig.Calibration & MFXSTM32L152_IDD_CTRL_CAL_DIS); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_CTRL, value); + + /* Idd pre delay configuration: unit and value*/ + value = (MfxIddConfig.PreDelayUnit & MFXSTM32L152_IDD_PREDELAY_UNIT) | + (MfxIddConfig.PreDelayValue & MFXSTM32L152_IDD_PREDELAY_VALUE); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_PRE_DELAY, value); + + /* Shunt 0 register value: MSB then LSB */ + value = (uint8_t) (MfxIddConfig.Shunt0Value >> 8); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SHUNT0_MSB, value); + value = (uint8_t) (MfxIddConfig.Shunt0Value); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SHUNT0_LSB, value); + + /* Shunt 1 register value: MSB then LSB */ + value = (uint8_t) (MfxIddConfig.Shunt1Value >> 8); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SHUNT1_MSB, value); + value = (uint8_t) (MfxIddConfig.Shunt1Value); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SHUNT1_LSB, value); + + /* Shunt 2 register value: MSB then LSB */ + value = (uint8_t) (MfxIddConfig.Shunt2Value >> 8); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SHUNT2_MSB, value); + value = (uint8_t) (MfxIddConfig.Shunt2Value); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SHUNT2_LSB, value); + + /* Shunt 3 register value: MSB then LSB */ + value = (uint8_t) (MfxIddConfig.Shunt3Value >> 8); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SHUNT3_MSB, value); + value = (uint8_t) (MfxIddConfig.Shunt3Value); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SHUNT3_LSB, value); + + /* Shunt 4 register value: MSB then LSB */ + value = (uint8_t) (MfxIddConfig.Shunt4Value >> 8); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SHUNT4_MSB, value); + value = (uint8_t) (MfxIddConfig.Shunt4Value); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SHUNT4_LSB, value); + + /* Shunt 0 stabilization delay */ + value = MfxIddConfig.Shunt0StabDelay; + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SH0_STABILIZATION, value); + + /* Shunt 1 stabilization delay */ + value = MfxIddConfig.Shunt1StabDelay; + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SH1_STABILIZATION, value); + + /* Shunt 2 stabilization delay */ + value = MfxIddConfig.Shunt2StabDelay; + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SH2_STABILIZATION, value); + + /* Shunt 3 stabilization delay */ + value = MfxIddConfig.Shunt3StabDelay; + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SH3_STABILIZATION, value); + + /* Shunt 4 stabilization delay */ + value = MfxIddConfig.Shunt4StabDelay; + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SH4_STABILIZATION, value); + + /* Idd ampli gain value: MSB then LSB */ + value = (uint8_t) (MfxIddConfig.AmpliGain >> 8); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_GAIN_MSB, value); + value = (uint8_t) (MfxIddConfig.AmpliGain); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_GAIN_LSB, value); + + /* Idd VDD min value: MSB then LSB */ + value = (uint8_t) (MfxIddConfig.VddMin >> 8); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_VDD_MIN_MSB, value); + value = (uint8_t) (MfxIddConfig.VddMin); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_VDD_MIN_LSB, value); + + /* Idd number of measurements */ + value = MfxIddConfig.MeasureNb; + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_NBR_OF_MEAS, value); + + /* Idd delta delay configuration: unit and value */ + value = (MfxIddConfig.DeltaDelayUnit & MFXSTM32L152_IDD_DELTADELAY_UNIT) | + (MfxIddConfig.DeltaDelayValue & MFXSTM32L152_IDD_DELTADELAY_VALUE); + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_MEAS_DELTA_DELAY, value); + + /* Idd number of shut on board */ + value = MfxIddConfig.ShuntNbOnBoard; + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SHUNTS_ON_BOARD, value); +} + +/** + * @brief This function allows to modify number of shunt used for a measurement + * @param DeviceAddr: Device address on communication Bus + * @retval None. + */ +void mfxstm32l152_IDD_ConfigShuntNbLimit(uint16_t DeviceAddr, uint8_t ShuntNbLimit) +{ + uint8_t mode = 0; + + /* Get the current register value */ + mode = MFX_IO_Read((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_CTRL); + + /* Clear number of shunt limit */ + mode &= ~(MFXSTM32L152_IDD_CTRL_SHUNT_NB); + + /* Clear number of shunt limit */ + mode |= ((ShuntNbLimit << 1) & MFXSTM32L152_IDD_CTRL_SHUNT_NB); + + /* Write noewx desired limit */ + MFX_IO_Write((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_CTRL, mode); +} + +/** + * @brief Get Idd current value + * @param DeviceAddr: Device address on communication Bus + * @param ReadValue: Pointer on value to be read + * @retval Idd value in 10 nA. + */ +void mfxstm32l152_IDD_GetValue(uint16_t DeviceAddr, uint32_t *ReadValue) +{ + uint8_t data[3]; + + MFX_IO_ReadMultiple((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_VALUE_MSB, data, sizeof(data)) ; + + /* Recompose Idd current value */ + *ReadValue = (data[0] << 16) | (data[1] << 8) | data[2]; + +} + +/** + * @brief Get Last shunt used for measurement + * @param DeviceAddr: Device address on communication Bus + * @retval Last shunt used + */ +uint8_t mfxstm32l152_IDD_GetShuntUsed(uint16_t DeviceAddr) +{ + return(MFX_IO_Read((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_IDD_SHUNT_USED)); +} + +/** + * @brief Configure mfx to enable Idd interrupt + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_IDD_EnableIT(uint16_t DeviceAddr) +{ + MFX_IO_ITConfig(); + + /* Enable global IDD interrupt source */ + mfxstm32l152_EnableITSource(DeviceAddr, MFXSTM32L152_IRQ_IDD); +} + +/** + * @brief Clear Idd global interrupt + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_IDD_ClearIT(uint16_t DeviceAddr) +{ + /* Clear the global IDD interrupt source */ + mfxstm32l152_ClearGlobalIT(DeviceAddr, MFXSTM32L152_IRQ_IDD); +} + +/** + * @brief get Idd interrupt status + * @param DeviceAddr: Device address on communication Bus. + * @retval IDD interrupts status + */ +uint8_t mfxstm32l152_IDD_GetITStatus(uint16_t DeviceAddr) +{ + /* Return IDD interrupt status */ + return(mfxstm32l152_GlobalITStatus(DeviceAddr, MFXSTM32L152_IRQ_IDD)); +} + +/** + * @brief disable Idd interrupt + * @param DeviceAddr: Device address on communication Bus. + * @retval None. + */ +void mfxstm32l152_IDD_DisableIT(uint16_t DeviceAddr) +{ + /* Disable global IDD interrupt source */ + mfxstm32l152_DisableITSource(DeviceAddr, MFXSTM32L152_IRQ_IDD); +} + + +/* ------------------------------------------------------------------ */ +/* --------------------- ERROR MANAGEMENT --------------------------- */ +/* ------------------------------------------------------------------ */ + +/** + * @brief Read Error Source. + * @param DeviceAddr: Device address on communication Bus. + * @retval Error message code with error source + */ +uint8_t mfxstm32l152_Error_ReadSrc(uint16_t DeviceAddr) +{ + /* Get the current source register value */ + return(MFX_IO_Read((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_ERROR_SRC)); +} + +/** + * @brief Read Error Message + * @param DeviceAddr: Device address on communication Bus. + * @retval Error message code with error source + */ +uint8_t mfxstm32l152_Error_ReadMsg(uint16_t DeviceAddr) +{ + /* Get the current message register value */ + return(MFX_IO_Read((uint8_t) DeviceAddr, MFXSTM32L152_REG_ADR_ERROR_MSG)); +} + +/** + * @brief Enable Error global interrupt + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ + +void mfxstm32l152_Error_EnableIT(uint16_t DeviceAddr) +{ + MFX_IO_ITConfig(); + + /* Enable global Error interrupt source */ + mfxstm32l152_EnableITSource(DeviceAddr, MFXSTM32L152_IRQ_ERROR); +} + +/** + * @brief Clear Error global interrupt + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void mfxstm32l152_Error_ClearIT(uint16_t DeviceAddr) +{ + /* Clear the global Error interrupt source */ + mfxstm32l152_ClearGlobalIT(DeviceAddr, MFXSTM32L152_IRQ_ERROR); +} + +/** + * @brief get Error interrupt status + * @param DeviceAddr: Device address on communication Bus. + * @retval Error interrupts status + */ +uint8_t mfxstm32l152_Error_GetITStatus(uint16_t DeviceAddr) +{ + /* Return Error interrupt status */ + return(mfxstm32l152_GlobalITStatus(DeviceAddr, MFXSTM32L152_IRQ_ERROR)); +} + +/** + * @brief disable Error interrupt + * @param DeviceAddr: Device address on communication Bus. + * @retval None. + */ +void mfxstm32l152_Error_DisableIT(uint16_t DeviceAddr) +{ + /* Disable global Error interrupt source */ + mfxstm32l152_DisableITSource(DeviceAddr, MFXSTM32L152_IRQ_ERROR); +} + +/** + * @brief FOR DEBUG ONLY + */ +uint8_t mfxstm32l152_ReadReg(uint16_t DeviceAddr, uint8_t RegAddr) +{ + /* Get the current register value */ + return(MFX_IO_Read((uint8_t) DeviceAddr, RegAddr)); +} + +void mfxstm32l152_WriteReg(uint16_t DeviceAddr, uint8_t RegAddr, uint8_t Value) +{ + /* set the current register value */ + MFX_IO_Write((uint8_t) DeviceAddr, RegAddr, Value); +} + +/* ------------------------------------------------------------------ */ +/* ----------------------- Private functions ------------------------ */ +/* ------------------------------------------------------------------ */ +/** + * @brief Check if the device instance of the selected address is already registered + * and return its index + * @param DeviceAddr: Device address on communication Bus. + * @retval Index of the device instance if registered, 0xFF if not. + */ +static uint8_t mfxstm32l152_GetInstance(uint16_t DeviceAddr) +{ + uint8_t idx = 0; + + /* Check all the registered instances */ + for(idx = 0; idx < MFXSTM32L152_MAX_INSTANCE ; idx ++) + { + if(mfxstm32l152[idx] == DeviceAddr) + { + return idx; + } + } + + return 0xFF; +} + +/** + * @brief Release registered device instance + * @param DeviceAddr: Device address on communication Bus. + * @retval Index of released device instance, 0xFF if not. + */ +static uint8_t mfxstm32l152_ReleaseInstance(uint16_t DeviceAddr) +{ + uint8_t idx = 0; + + /* Check for all the registered instances */ + for(idx = 0; idx < MFXSTM32L152_MAX_INSTANCE ; idx ++) + { + if(mfxstm32l152[idx] == DeviceAddr) + { + mfxstm32l152[idx] = 0; + return idx; + } + } + return 0xFF; +} + +/** + * @brief Internal routine + * @param DeviceAddr: Device address on communication Bus. + * @param RegisterAddr: Register Address + * @param PinPosition: Pin [0:23] + * @param PinValue: 0/1 + * @retval None + */ +void mfxstm32l152_reg24_setPinValue(uint16_t DeviceAddr, uint8_t RegisterAddr, uint32_t PinPosition, uint8_t PinValue ) +{ + uint8_t tmp = 0; + uint8_t pin_0_7, pin_8_15, pin_16_23; + + pin_0_7 = PinPosition & 0x0000ff; + pin_8_15 = PinPosition >> 8; + pin_8_15 = pin_8_15 & 0x00ff; + pin_16_23 = PinPosition >> 16; + + if (pin_0_7) + { + /* Get the current register value */ + tmp = MFX_IO_Read(DeviceAddr, RegisterAddr); + + /* Set the selected pin direction */ + if (PinValue != 0) + { + tmp |= (uint8_t)pin_0_7; + } + else + { + tmp &= ~(uint8_t)pin_0_7; + } + + /* Set the new register value */ + MFX_IO_Write(DeviceAddr, RegisterAddr, tmp); + } + + if (pin_8_15) + { + /* Get the current register value */ + tmp = MFX_IO_Read(DeviceAddr, RegisterAddr+1); + + /* Set the selected pin direction */ + if (PinValue != 0) + { + tmp |= (uint8_t)pin_8_15; + } + else + { + tmp &= ~(uint8_t)pin_8_15; + } + + /* Set the new register value */ + MFX_IO_Write(DeviceAddr, RegisterAddr+1, tmp); + } + + if (pin_16_23) + { + /* Get the current register value */ + tmp = MFX_IO_Read(DeviceAddr, RegisterAddr+2); + + /* Set the selected pin direction */ + if (PinValue != 0) + { + tmp |= (uint8_t)pin_16_23; + } + else + { + tmp &= ~(uint8_t)pin_16_23; + } + + /* Set the new register value */ + MFX_IO_Write(DeviceAddr, RegisterAddr+2, tmp); + } +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/mfxstm32l152/mfxstm32l152.h b/src/port_stm32f7/common/bsp_drivers/Components/mfxstm32l152/mfxstm32l152.h new file mode 100644 index 00000000..ab60ba60 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/mfxstm32l152/mfxstm32l152.h @@ -0,0 +1,666 @@ +/** + ****************************************************************************** + * @file mfxstm32l152.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for the + * mfxstm32l152.c IO expander driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MFXSTM32L152_H +#define __MFXSTM32L152_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "../Common/ts.h" +#include "../Common/io.h" +#include "../Common/idd.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Component + * @{ + */ + +/** @defgroup MFXSTM32L152 + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** @defgroup MFXSTM32L152_Exported_Types + * @{ + */ +typedef struct +{ + uint8_t SYS_CTRL; + uint8_t ERROR_SRC; + uint8_t ERROR_MSG; + uint8_t IRQ_OUT; + uint8_t IRQ_SRC_EN; + uint8_t IRQ_PENDING; + uint8_t IDD_CTRL; + uint8_t IDD_PRE_DELAY; + uint8_t IDD_SHUNT0_MSB; + uint8_t IDD_SHUNT0_LSB; + uint8_t IDD_SHUNT1_MSB; + uint8_t IDD_SHUNT1_LSB; + uint8_t IDD_SHUNT2_MSB; + uint8_t IDD_SHUNT2_LSB; + uint8_t IDD_SHUNT3_MSB; + uint8_t IDD_SHUNT3_LSB; + uint8_t IDD_SHUNT4_MSB; + uint8_t IDD_SHUNT4_LSB; + uint8_t IDD_GAIN_MSB; + uint8_t IDD_GAIN_LSB; + uint8_t IDD_VDD_MIN_MSB; + uint8_t IDD_VDD_MIN_LSB; + uint8_t IDD_VALUE_MSB; + uint8_t IDD_VALUE_MID; + uint8_t IDD_VALUE_LSB; + uint8_t IDD_CAL_OFFSET_MSB; + uint8_t IDD_CAL_OFFSET_LSB; + uint8_t IDD_SHUNT_USED; +}IDD_dbgTypeDef; + +/** + * @} + */ + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup MFXSTM32L152_Exported_Constants + * @{ + */ + + /** + * @brief MFX COMMON defines + */ + + /** + * @brief Register address: chip IDs (R) + */ +#define MFXSTM32L152_REG_ADR_ID ((uint8_t)0x00) + /** + * @brief Register address: chip FW_VERSION (R) + */ +#define MFXSTM32L152_REG_ADR_FW_VERSION_MSB ((uint8_t)0x01) +#define MFXSTM32L152_REG_ADR_FW_VERSION_LSB ((uint8_t)0x00) + /** + * @brief Register address: System Control Register (R/W) + */ +#define MFXSTM32L152_REG_ADR_SYS_CTRL ((uint8_t)0x40) + /** + * @brief Register address: Vdd monitoring (R) + */ +#define MFXSTM32L152_REG_ADR_VDD_REF_MSB ((uint8_t)0x06) +#define MFXSTM32L152_REG_ADR_VDD_REF_LSB ((uint8_t)0x07) + /** + * @brief Register address: Error source + */ +#define MFXSTM32L152_REG_ADR_ERROR_SRC ((uint8_t)0x03) + /** + * @brief Register address: Error Message + */ +#define MFXSTM32L152_REG_ADR_ERROR_MSG ((uint8_t)0x04) + + /** + * @brief Reg Addr IRQs: to config the pin that informs Main MCU that MFX events appear + */ +#define MFXSTM32L152_REG_ADR_MFX_IRQ_OUT ((uint8_t)0x41) + /** + * @brief Reg Addr IRQs: to select the events which activate the MFXSTM32L152_IRQ_OUT signal + */ +#define MFXSTM32L152_REG_ADR_IRQ_SRC_EN ((uint8_t)0x42) + /** + * @brief Reg Addr IRQs: the Main MCU must read the IRQ_PENDING register to know the interrupt reason + */ +#define MFXSTM32L152_REG_ADR_IRQ_PENDING ((uint8_t)0x08) + /** + * @brief Reg Addr IRQs: the Main MCU must acknowledge it thanks to a writing access to the IRQ_ACK register + */ +#define MFXSTM32L152_REG_ADR_IRQ_ACK ((uint8_t)0x44) + + /** + * @brief MFXSTM32L152_REG_ADR_ID choices + */ +#define MFXSTM32L152_ID_1 ((uint8_t)0x7B) +#define MFXSTM32L152_ID_2 ((uint8_t)0x79) + + /** + * @brief MFXSTM32L152_REG_ADR_SYS_CTRL choices + */ +#define MFXSTM32L152_SWRST ((uint8_t)0x80) +#define MFXSTM32L152_STANDBY ((uint8_t)0x40) +#define MFXSTM32L152_ALTERNATE_GPIO_EN ((uint8_t)0x08) /* by the way if IDD and TS are enabled they take automatically the AF pins*/ +#define MFXSTM32L152_IDD_EN ((uint8_t)0x04) +#define MFXSTM32L152_TS_EN ((uint8_t)0x02) +#define MFXSTM32L152_GPIO_EN ((uint8_t)0x01) + + /** + * @brief MFXSTM32L152_REG_ADR_ERROR_SRC choices + */ +#define MFXSTM32L152_IDD_ERROR_SRC ((uint8_t)0x04) /* Error raised by Idd */ +#define MFXSTM32L152_TS_ERROR_SRC ((uint8_t)0x02) /* Error raised by Touch Screen */ +#define MFXSTM32L152_GPIO_ERROR_SRC ((uint8_t)0x01) /* Error raised by Gpio */ + + /** + * @brief MFXSTM32L152_REG_ADR_MFX_IRQ_OUT choices + */ +#define MFXSTM32L152_OUT_PIN_TYPE_OPENDRAIN ((uint8_t)0x00) +#define MFXSTM32L152_OUT_PIN_TYPE_PUSHPULL ((uint8_t)0x01) +#define MFXSTM32L152_OUT_PIN_POLARITY_LOW ((uint8_t)0x00) +#define MFXSTM32L152_OUT_PIN_POLARITY_HIGH ((uint8_t)0x02) + + /** + * @brief REG_ADR_IRQ_SRC_EN, REG_ADR_IRQ_PENDING & REG_ADR_IRQ_ACK choices + */ +#define MFXSTM32L152_IRQ_TS_OVF ((uint8_t)0x80) /* TouchScreen FIFO Overflow irq*/ +#define MFXSTM32L152_IRQ_TS_FULL ((uint8_t)0x40) /* TouchScreen FIFO Full irq*/ +#define MFXSTM32L152_IRQ_TS_TH ((uint8_t)0x20) /* TouchScreen FIFO threshold triggered irq*/ +#define MFXSTM32L152_IRQ_TS_NE ((uint8_t)0x10) /* TouchScreen FIFO Not Empty irq*/ +#define MFXSTM32L152_IRQ_TS_DET ((uint8_t)0x08) /* TouchScreen Detect irq*/ +#define MFXSTM32L152_IRQ_ERROR ((uint8_t)0x04) /* Error message from MFXSTM32L152 firmware irq */ +#define MFXSTM32L152_IRQ_IDD ((uint8_t)0x02) /* IDD function irq */ +#define MFXSTM32L152_IRQ_GPIO ((uint8_t)0x01) /* General GPIO irq (only for SRC_EN and PENDING) */ +#define MFXSTM32L152_IRQ_ALL ((uint8_t)0xFF) /* All global interrupts */ +#define MFXSTM32L152_IRQ_TS (MFXSTM32L152_IRQ_TS_DET | MFXSTM32L152_IRQ_TS_NE | MFXSTM32L152_IRQ_TS_TH | MFXSTM32L152_IRQ_TS_FULL | MFXSTM32L152_IRQ_TS_OVF ) + + + /** + * @brief GPIO: 24 programmable input/output called MFXSTM32L152_GPIO[23:0] are provided + */ + + /** + * @brief Reg addr: GPIO DIRECTION (R/W): GPIO pins direction: (0) input, (1) output. + */ +#define MFXSTM32L152_REG_ADR_GPIO_DIR1 ((uint8_t)0x60) /* gpio [0:7] */ +#define MFXSTM32L152_REG_ADR_GPIO_DIR2 ((uint8_t)0x61) /* gpio [8:15] */ +#define MFXSTM32L152_REG_ADR_GPIO_DIR3 ((uint8_t)0x62) /* agpio [0:7] */ + /** + * @brief Reg addr: GPIO TYPE (R/W): If GPIO in output: (0) output push pull, (1) output open drain. + * If GPIO in input: (0) input without pull resistor, (1) input with pull resistor. + */ +#define MFXSTM32L152_REG_ADR_GPIO_TYPE1 ((uint8_t)0x64) /* gpio [0:7] */ +#define MFXSTM32L152_REG_ADR_GPIO_TYPE2 ((uint8_t)0x65) /* gpio [8:15] */ +#define MFXSTM32L152_REG_ADR_GPIO_TYPE3 ((uint8_t)0x66) /* agpio [0:7] */ + /** + * @brief Reg addr: GPIO PULL_UP_PULL_DOWN (R/W): discussion open with Jean Claude + */ +#define MFXSTM32L152_REG_ADR_GPIO_PUPD1 ((uint8_t)0x68) /* gpio [0:7] */ +#define MFXSTM32L152_REG_ADR_GPIO_PUPD2 ((uint8_t)0x69) /* gpio [8:15] */ +#define MFXSTM32L152_REG_ADR_GPIO_PUPD3 ((uint8_t)0x6A) /* agpio [0:7] */ + /** + * @brief Reg addr: GPIO SET (W): When GPIO is in output mode, write (1) puts the corresponding GPO in High level. + */ +#define MFXSTM32L152_REG_ADR_GPO_SET1 ((uint8_t)0x6C) /* gpio [0:7] */ +#define MFXSTM32L152_REG_ADR_GPO_SET2 ((uint8_t)0x6D) /* gpio [8:15] */ +#define MFXSTM32L152_REG_ADR_GPO_SET3 ((uint8_t)0x6E) /* agpio [0:7] */ + /** + * @brief Reg addr: GPIO CLEAR (W): When GPIO is in output mode, write (1) puts the corresponding GPO in Low level. + */ +#define MFXSTM32L152_REG_ADR_GPO_CLR1 ((uint8_t)0x70) /* gpio [0:7] */ +#define MFXSTM32L152_REG_ADR_GPO_CLR2 ((uint8_t)0x71) /* gpio [8:15] */ +#define MFXSTM32L152_REG_ADR_GPO_CLR3 ((uint8_t)0x72) /* agpio [0:7] */ + /** + * @brief Reg addr: GPIO STATE (R): Give state of the GPIO pin. + */ +#define MFXSTM32L152_REG_ADR_GPIO_STATE1 ((uint8_t)0x10) /* gpio [0:7] */ +#define MFXSTM32L152_REG_ADR_GPIO_STATE2 ((uint8_t)0x11) /* gpio [8:15] */ +#define MFXSTM32L152_REG_ADR_GPIO_STATE3 ((uint8_t)0x12) /* agpio [0:7] */ + + /** + * @brief GPIO IRQ_GPIs + */ +/* GPIOs can INDIVIDUALLY generate interruption to the Main MCU thanks to the MFXSTM32L152_IRQ_OUT signal */ +/* the general MFXSTM32L152_IRQ_GPIO_SRC_EN shall be enabled too */ + /** + * @brief GPIO IRQ_GPI_SRC1/2/3 (R/W): registers enable or not the feature to generate irq + */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_SRC1 ((uint8_t)0x48) /* gpio [0:7] */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_SRC2 ((uint8_t)0x49) /* gpio [8:15] */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_SRC3 ((uint8_t)0x4A) /* agpio [0:7] */ + /** + * @brief GPIO IRQ_GPI_EVT1/2/3 (R/W): Irq generated on level (0) or edge (1). + */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_EVT1 ((uint8_t)0x4C) /* gpio [0:7] */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_EVT2 ((uint8_t)0x4D) /* gpio [8:15] */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_EVT3 ((uint8_t)0x4E) /* agpio [0:7] */ + /** + * @brief GPIO IRQ_GPI_TYPE1/2/3 (R/W): Irq generated on (0) : Low level or Falling edge. (1) : High level or Rising edge. + */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_TYPE1 ((uint8_t)0x50) /* gpio [0:7] */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_TYPE2 ((uint8_t)0x51) /* gpio [8:15] */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_TYPE3 ((uint8_t)0x52) /* agpio [0:7] */ + /** + * @brief GPIO IRQ_GPI_PENDING1/2/3 (R): irq occurs + */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_PENDING1 ((uint8_t)0x0C) /* gpio [0:7] */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_PENDING2 ((uint8_t)0x0D) /* gpio [8:15] */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_PENDING3 ((uint8_t)0x0E) /* agpio [0:7] */ + /** + * @brief GPIO IRQ_GPI_ACK1/2/3 (W): Write (1) to acknowledge IRQ event + */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_ACK1 ((uint8_t)0x54) /* gpio [0:7] */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_ACK2 ((uint8_t)0x55) /* gpio [8:15] */ +#define MFXSTM32L152_REG_ADR_IRQ_GPI_ACK3 ((uint8_t)0x56) /* agpio [0:7] */ + + + /** + * @brief GPIO: IO Pins definition + */ +#define MFXSTM32L152_GPIO_PIN_0 ((uint32_t)0x0001) +#define MFXSTM32L152_GPIO_PIN_1 ((uint32_t)0x0002) +#define MFXSTM32L152_GPIO_PIN_2 ((uint32_t)0x0004) +#define MFXSTM32L152_GPIO_PIN_3 ((uint32_t)0x0008) +#define MFXSTM32L152_GPIO_PIN_4 ((uint32_t)0x0010) +#define MFXSTM32L152_GPIO_PIN_5 ((uint32_t)0x0020) +#define MFXSTM32L152_GPIO_PIN_6 ((uint32_t)0x0040) +#define MFXSTM32L152_GPIO_PIN_7 ((uint32_t)0x0080) + +#define MFXSTM32L152_GPIO_PIN_8 ((uint32_t)0x0100) +#define MFXSTM32L152_GPIO_PIN_9 ((uint32_t)0x0200) +#define MFXSTM32L152_GPIO_PIN_10 ((uint32_t)0x0400) +#define MFXSTM32L152_GPIO_PIN_11 ((uint32_t)0x0800) +#define MFXSTM32L152_GPIO_PIN_12 ((uint32_t)0x1000) +#define MFXSTM32L152_GPIO_PIN_13 ((uint32_t)0x2000) +#define MFXSTM32L152_GPIO_PIN_14 ((uint32_t)0x4000) +#define MFXSTM32L152_GPIO_PIN_15 ((uint32_t)0x8000) + +#define MFXSTM32L152_GPIO_PIN_16 ((uint32_t)0x010000) +#define MFXSTM32L152_GPIO_PIN_17 ((uint32_t)0x020000) +#define MFXSTM32L152_GPIO_PIN_18 ((uint32_t)0x040000) +#define MFXSTM32L152_GPIO_PIN_19 ((uint32_t)0x080000) +#define MFXSTM32L152_GPIO_PIN_20 ((uint32_t)0x100000) +#define MFXSTM32L152_GPIO_PIN_21 ((uint32_t)0x200000) +#define MFXSTM32L152_GPIO_PIN_22 ((uint32_t)0x400000) +#define MFXSTM32L152_GPIO_PIN_23 ((uint32_t)0x800000) + +#define MFXSTM32L152_AGPIO_PIN_0 MFXSTM32L152_GPIO_PIN_16 +#define MFXSTM32L152_AGPIO_PIN_1 MFXSTM32L152_GPIO_PIN_17 +#define MFXSTM32L152_AGPIO_PIN_2 MFXSTM32L152_GPIO_PIN_18 +#define MFXSTM32L152_AGPIO_PIN_3 MFXSTM32L152_GPIO_PIN_19 +#define MFXSTM32L152_AGPIO_PIN_4 MFXSTM32L152_GPIO_PIN_20 +#define MFXSTM32L152_AGPIO_PIN_5 MFXSTM32L152_GPIO_PIN_21 +#define MFXSTM32L152_AGPIO_PIN_6 MFXSTM32L152_GPIO_PIN_22 +#define MFXSTM32L152_AGPIO_PIN_7 MFXSTM32L152_GPIO_PIN_23 + +#define MFXSTM32L152_GPIO_PINS_ALL ((uint32_t)0xFFFFFF) + + /** + * @brief GPIO: constant + */ +#define MFXSTM32L152_GPIO_DIR_IN ((uint8_t)0x0) +#define MFXSTM32L152_GPIO_DIR_OUT ((uint8_t)0x1) +#define MFXSTM32L152_IRQ_GPI_EVT_LEVEL ((uint8_t)0x0) +#define MFXSTM32L152_IRQ_GPI_EVT_EDGE ((uint8_t)0x1) +#define MFXSTM32L152_IRQ_GPI_TYPE_LLFE ((uint8_t)0x0) /* Low Level Falling Edge */ +#define MFXSTM32L152_IRQ_GPI_TYPE_HLRE ((uint8_t)0x1) /*High Level Raising Edge */ +#define MFXSTM32L152_GPI_WITHOUT_PULL_RESISTOR ((uint8_t)0x0) +#define MFXSTM32L152_GPI_WITH_PULL_RESISTOR ((uint8_t)0x1) +#define MFXSTM32L152_GPO_PUSH_PULL ((uint8_t)0x0) +#define MFXSTM32L152_GPO_OPEN_DRAIN ((uint8_t)0x1) +#define MFXSTM32L152_GPIO_PULL_DOWN ((uint8_t)0x0) +#define MFXSTM32L152_GPIO_PULL_UP ((uint8_t)0x1) + + + /** + * @brief TOUCH SCREEN Registers + */ + + /** + * @brief Touch Screen Registers + */ +#define MFXSTM32L152_TS_SETTLING ((uint8_t)0xA0) +#define MFXSTM32L152_TS_TOUCH_DET_DELAY ((uint8_t)0xA1) +#define MFXSTM32L152_TS_AVE ((uint8_t)0xA2) +#define MFXSTM32L152_TS_TRACK ((uint8_t)0xA3) +#define MFXSTM32L152_TS_FIFO_TH ((uint8_t)0xA4) +#define MFXSTM32L152_TS_FIFO_STA ((uint8_t)0x20) +#define MFXSTM32L152_TS_FIFO_LEVEL ((uint8_t)0x21) +#define MFXSTM32L152_TS_XY_DATA ((uint8_t)0x24) + + /** + * @brief TS registers masks + */ +#define MFXSTM32L152_TS_CTRL_STATUS ((uint8_t)0x08) +#define MFXSTM32L152_TS_CLEAR_FIFO ((uint8_t)0x80) + + +/** + * @brief Register address: Idd control register (R/W) + */ +#define MFXSTM32L152_REG_ADR_IDD_CTRL ((uint8_t)0x80) + +/** + * @brief Register address: Idd pre delay register (R/W) + */ +#define MFXSTM32L152_REG_ADR_IDD_PRE_DELAY ((uint8_t)0x81) + +/** + * @brief Register address: Idd Shunt registers (R/W) + */ +#define MFXSTM32L152_REG_ADR_IDD_SHUNT0_MSB ((uint8_t)0x82) +#define MFXSTM32L152_REG_ADR_IDD_SHUNT0_LSB ((uint8_t)0x83) +#define MFXSTM32L152_REG_ADR_IDD_SHUNT1_MSB ((uint8_t)0x84) +#define MFXSTM32L152_REG_ADR_IDD_SHUNT1_LSB ((uint8_t)0x85) +#define MFXSTM32L152_REG_ADR_IDD_SHUNT2_MSB ((uint8_t)0x86) +#define MFXSTM32L152_REG_ADR_IDD_SHUNT2_LSB ((uint8_t)0x87) +#define MFXSTM32L152_REG_ADR_IDD_SHUNT3_MSB ((uint8_t)0x88) +#define MFXSTM32L152_REG_ADR_IDD_SHUNT3_LSB ((uint8_t)0x89) +#define MFXSTM32L152_REG_ADR_IDD_SHUNT4_MSB ((uint8_t)0x8A) +#define MFXSTM32L152_REG_ADR_IDD_SHUNT4_LSB ((uint8_t)0x8B) + +/** + * @brief Register address: Idd ampli gain register (R/W) + */ +#define MFXSTM32L152_REG_ADR_IDD_GAIN_MSB ((uint8_t)0x8C) +#define MFXSTM32L152_REG_ADR_IDD_GAIN_LSB ((uint8_t)0x8D) + +/** + * @brief Register address: Idd VDD min register (R/W) + */ +#define MFXSTM32L152_REG_ADR_IDD_VDD_MIN_MSB ((uint8_t)0x8E) +#define MFXSTM32L152_REG_ADR_IDD_VDD_MIN_LSB ((uint8_t)0x8F) + +/** + * @brief Register address: Idd value register (R) + */ +#define MFXSTM32L152_REG_ADR_IDD_VALUE_MSB ((uint8_t)0x14) +#define MFXSTM32L152_REG_ADR_IDD_VALUE_MID ((uint8_t)0x15) +#define MFXSTM32L152_REG_ADR_IDD_VALUE_LSB ((uint8_t)0x16) + +/** + * @brief Register address: Idd calibration offset register (R) + */ +#define MFXSTM32L152_REG_ADR_IDD_CAL_OFFSET_MSB ((uint8_t)0x18) +#define MFXSTM32L152_REG_ADR_IDD_CAL_OFFSET_LSB ((uint8_t)0x19) + +/** + * @brief Register address: Idd shunt used offset register (R) + */ +#define MFXSTM32L152_REG_ADR_IDD_SHUNT_USED ((uint8_t)0x1A) + +/** + * @brief Register address: shunt stabilisation delay registers (R/W) + */ +#define MFXSTM32L152_REG_ADR_IDD_SH0_STABILIZATION ((uint8_t)0x90) +#define MFXSTM32L152_REG_ADR_IDD_SH1_STABILIZATION ((uint8_t)0x91) +#define MFXSTM32L152_REG_ADR_IDD_SH2_STABILIZATION ((uint8_t)0x92) +#define MFXSTM32L152_REG_ADR_IDD_SH3_STABILIZATION ((uint8_t)0x93) +#define MFXSTM32L152_REG_ADR_IDD_SH4_STABILIZATION ((uint8_t)0x94) + +/** + * @brief Register address: Idd number of measurements register (R/W) + */ +#define MFXSTM32L152_REG_ADR_IDD_NBR_OF_MEAS ((uint8_t)0x96) + +/** + * @brief Register address: Idd delta delay between 2 measurements register (R/W) + */ +#define MFXSTM32L152_REG_ADR_IDD_MEAS_DELTA_DELAY ((uint8_t)0x97) + +/** + * @brief Register address: Idd number of shunt on board register (R/W) + */ +#define MFXSTM32L152_REG_ADR_IDD_SHUNTS_ON_BOARD ((uint8_t)0x98) + + + +/** @defgroup IDD_Control_Register_Defines IDD Control Register Defines + * @{ + */ +/** + * @brief IDD control register masks + */ +#define MFXSTM32L152_IDD_CTRL_REQ ((uint8_t)0x01) +#define MFXSTM32L152_IDD_CTRL_SHUNT_NB ((uint8_t)0x0E) +#define MFXSTM32L152_IDD_CTRL_VREF_DIS ((uint8_t)0x40) +#define MFXSTM32L152_IDD_CTRL_CAL_DIS ((uint8_t)0x80) + +/** + * @brief IDD Shunt Number + */ +#define MFXSTM32L152_IDD_SHUNT_NB_1 ((uint8_t) 0x01) +#define MFXSTM32L152_IDD_SHUNT_NB_2 ((uint8_t) 0x02) +#define MFXSTM32L152_IDD_SHUNT_NB_3 ((uint8_t) 0x03) +#define MFXSTM32L152_IDD_SHUNT_NB_4 ((uint8_t) 0x04) +#define MFXSTM32L152_IDD_SHUNT_NB_5 ((uint8_t) 0x05) + +/** + * @brief Vref Measurement + */ +#define MFXSTM32L152_IDD_VREF_AUTO_MEASUREMENT_ENABLE ((uint8_t) 0x00) +#define MFXSTM32L152_IDD_VREF_AUTO_MEASUREMENT_DISABLE ((uint8_t) 0x70) + +/** + * @brief IDD Calibration + */ +#define MFXSTM32L152_IDD_AUTO_CALIBRATION_ENABLE ((uint8_t) 0x00) +#define MFXSTM32L152_IDD_AUTO_CALIBRATION_DISABLE ((uint8_t) 0x80) +/** + * @} + */ + +/** @defgroup IDD_PreDelay_Defines IDD PreDelay Defines + * @{ + */ +/** + * @brief IDD PreDelay masks + */ +#define MFXSTM32L152_IDD_PREDELAY_UNIT ((uint8_t) 0x80) +#define MFXSTM32L152_IDD_PREDELAY_VALUE ((uint8_t) 0x7F) + + +/** + * @brief IDD PreDelay unit + */ +#define MFXSTM32L152_IDD_PREDELAY_0_5_MS ((uint8_t) 0x00) +#define MFXSTM32L152_IDD_PREDELAY_20_MS ((uint8_t) 0x80) +/** + * @} + */ + +/** @defgroup IDD_DeltaDelay_Defines IDD Delta DElay Defines + * @{ + */ +/** + * @brief IDD Delta Delay masks + */ +#define MFXSTM32L152_IDD_DELTADELAY_UNIT ((uint8_t) 0x80) +#define MFXSTM32L152_IDD_DELTADELAY_VALUE ((uint8_t) 0x7F) + + +/** + * @brief IDD Delta Delay unit + */ +#define MFXSTM32L152_IDD_DELTADELAY_0_5_MS ((uint8_t) 0x00) +#define MFXSTM32L152_IDD_DELTADELAY_20_MS ((uint8_t) 0x80) + + +/** + * @} + */ + +/** + * @} + */ + + +/* Exported macro ------------------------------------------------------------*/ + +/** @defgroup MFXSTM32L152_Exported_Macros + * @{ + */ + +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ + +/** @defgroup MFXSTM32L152_Exported_Functions + * @{ + */ + +/** + * @brief MFXSTM32L152 Control functions + */ +void mfxstm32l152_Init(uint16_t DeviceAddr); +void mfxstm32l152_DeInit(uint16_t DeviceAddr); +void mfxstm32l152_Reset(uint16_t DeviceAddr); +uint16_t mfxstm32l152_ReadID(uint16_t DeviceAddr); +uint16_t mfxstm32l152_ReadFwVersion(uint16_t DeviceAddr); +void mfxstm32l152_LowPower(uint16_t DeviceAddr); +void mfxstm32l152_WakeUp(uint16_t DeviceAddr); + +void mfxstm32l152_EnableITSource(uint16_t DeviceAddr, uint8_t Source); +void mfxstm32l152_DisableITSource(uint16_t DeviceAddr, uint8_t Source); +uint8_t mfxstm32l152_GlobalITStatus(uint16_t DeviceAddr, uint8_t Source); +void mfxstm32l152_ClearGlobalIT(uint16_t DeviceAddr, uint8_t Source); + +void mfxstm32l152_SetIrqOutPinPolarity(uint16_t DeviceAddr, uint8_t Polarity); +void mfxstm32l152_SetIrqOutPinType(uint16_t DeviceAddr, uint8_t Type); + + +/** + * @brief MFXSTM32L152 IO functionalities functions + */ +void mfxstm32l152_IO_Start(uint16_t DeviceAddr, uint32_t IO_Pin); +uint8_t mfxstm32l152_IO_Config(uint16_t DeviceAddr, uint32_t IO_Pin, IO_ModeTypedef IO_Mode); +void mfxstm32l152_IO_WritePin(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t PinState); +uint32_t mfxstm32l152_IO_ReadPin(uint16_t DeviceAddr, uint32_t IO_Pin); +void mfxstm32l152_IO_EnableIT(uint16_t DeviceAddr); +void mfxstm32l152_IO_DisableIT(uint16_t DeviceAddr); +uint32_t mfxstm32l152_IO_ITStatus(uint16_t DeviceAddr, uint32_t IO_Pin); +void mfxstm32l152_IO_ClearIT(uint16_t DeviceAddr, uint32_t IO_Pin); + +void mfxstm32l152_IO_InitPin(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t Direction); +void mfxstm32l152_IO_EnableAF(uint16_t DeviceAddr); +void mfxstm32l152_IO_DisableAF(uint16_t DeviceAddr); +void mfxstm32l152_IO_SetIrqTypeMode(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t Type); +void mfxstm32l152_IO_SetIrqEvtMode(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t Evt); +void mfxstm32l152_IO_EnablePinIT(uint16_t DeviceAddr, uint32_t IO_Pin); +void mfxstm32l152_IO_DisablePinIT(uint16_t DeviceAddr, uint32_t IO_Pin); + +/** + * @brief MFXSTM32L152 Touch screen functionalities functions + */ +void mfxstm32l152_TS_Start(uint16_t DeviceAddr); +uint8_t mfxstm32l152_TS_DetectTouch(uint16_t DeviceAddr); +void mfxstm32l152_TS_GetXY(uint16_t DeviceAddr, uint16_t *X, uint16_t *Y); +void mfxstm32l152_TS_EnableIT(uint16_t DeviceAddr); +void mfxstm32l152_TS_DisableIT(uint16_t DeviceAddr); +uint8_t mfxstm32l152_TS_ITStatus (uint16_t DeviceAddr); +void mfxstm32l152_TS_ClearIT (uint16_t DeviceAddr); + +/** + * @brief MFXSTM32L152 IDD current measurement functionalities functions + */ +void mfxstm32l152_IDD_Start(uint16_t DeviceAddr); +void mfxstm32l152_IDD_Config(uint16_t DeviceAddr, IDD_ConfigTypeDef MfxIddConfig); +void mfxstm32l152_IDD_ConfigShuntNbLimit(uint16_t DeviceAddr, uint8_t ShuntNbLimit); +void mfxstm32l152_IDD_GetValue(uint16_t DeviceAddr, uint32_t *ReadValue); +uint8_t mfxstm32l152_IDD_GetShuntUsed(uint16_t DeviceAddr); +void mfxstm32l152_IDD_EnableIT(uint16_t DeviceAddr); +void mfxstm32l152_IDD_ClearIT(uint16_t DeviceAddr); +uint8_t mfxstm32l152_IDD_GetITStatus(uint16_t DeviceAddr); +void mfxstm32l152_IDD_DisableIT(uint16_t DeviceAddr); + +/** + * @brief MFXSTM32L152 Error management functions + */ +uint8_t mfxstm32l152_Error_ReadSrc(uint16_t DeviceAddr); +uint8_t mfxstm32l152_Error_ReadMsg(uint16_t DeviceAddr); +void mfxstm32l152_Error_EnableIT(uint16_t DeviceAddr); +void mfxstm32l152_Error_ClearIT(uint16_t DeviceAddr); +uint8_t mfxstm32l152_Error_GetITStatus(uint16_t DeviceAddr); +void mfxstm32l152_Error_DisableIT(uint16_t DeviceAddr); + +uint8_t mfxstm32l152_ReadReg(uint16_t DeviceAddr, uint8_t RegAddr); +void mfxstm32l152_WriteReg(uint16_t DeviceAddr, uint8_t RegAddr, uint8_t Value); + + + +/** + * @brief iobus prototypes (they should be defined in common/stm32_iobus.h) + */ +void MFX_IO_Init(void); +void MFX_IO_DeInit(void); +void MFX_IO_ITConfig (void); +void MFX_IO_EnableWakeupPin(void); +void MFX_IO_Wakeup(void); +void MFX_IO_Delay(uint32_t delay); +void MFX_IO_Write(uint16_t addr, uint8_t reg, uint8_t value); +uint8_t MFX_IO_Read(uint16_t addr, uint8_t reg); +uint16_t MFX_IO_ReadMultiple(uint16_t addr, uint8_t reg, uint8_t *buffer, uint16_t length); + +/** + * @} + */ + +/* Touch screen driver structure */ +extern TS_DrvTypeDef mfxstm32l152_ts_drv; + +/* IO driver structure */ +extern IO_DrvTypeDef mfxstm32l152_io_drv; + +/* IDD driver structure */ +extern IDD_DrvTypeDef mfxstm32l152_idd_drv; + + +#ifdef __cplusplus +} +#endif +#endif /* __MFXSTM32L152_H */ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/mx25l512/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/mx25l512/Release_Notes.html new file mode 100644 index 00000000..f99c285f --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/mx25l512/Release_Notes.html @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + Release Notes for STM32 BSP Components Drivers + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for MX25L512 Component Driver

+

Copyright +2016 STMicroelectronics

+

+
+

 

+ + + + + + +

Update History

V1.0.3 / 02-June-2017

Main Changes

  • Update comments to be used for PDSC generation

V1.0.2 +/ 13-December-2016

+ + + + + +

Main +Changes

+ + + + + + + + + + + + + +
    +
  • Replace QPI_* with QSPI_*
  • +
  • Add alias for comaptibility
    +
  • +
+

V1.0.1 +/ 03-August-2016

+ + + + +

Main +Changes

+ + + + + + + + + + + +
    +
  • Remove extra comment
    +
  • +
+ +

V1.0.0 +/ 22-April-2016

+ + +

Main +Changes

+ + + + + + + + + + +
    +
  • First official release
  • +
+

License

+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+
For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32
+

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/mx25l512/mx25l512.h b/src/port_stm32f7/common/bsp_drivers/Components/mx25l512/mx25l512.h new file mode 100644 index 00000000..3cb99ff5 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/mx25l512/mx25l512.h @@ -0,0 +1,227 @@ +/** + ****************************************************************************** + * @file mx25l512.h + * @author MCD Application Team + * @brief This file contains all the description of the MX25L51245G QSPI memory. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MX25L512_H +#define __MX25L512_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup MX25L512 + * @{ + */ + +/** @defgroup MX25L512_Exported_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup MX25L512_Exported_Constants + * @{ + */ + +/** + * @brief MX25L512 Configuration + */ +#define MX25L512_FLASH_SIZE 0x4000000 /* 512 MBits => 64MBytes */ +#define MX25L512_SECTOR_SIZE 0x10000 /* 1024 sectors of 64KBytes */ +#define MX25L512_SUBSECTOR_SIZE 0x1000 /* 16384 subsectors of 4kBytes */ +#define MX25L512_PAGE_SIZE 0x100 /* 262144 pages of 256 bytes */ + +#define MX25L512_DUMMY_CYCLES_READ_QUAD 3 +#define MX25L512_DUMMY_CYCLES_READ 8 +#define MX25L512_DUMMY_CYCLES_READ_QUAD_IO 10 +#define MX25L512_DUMMY_CYCLES_READ_DTR 6 +#define MX25L512_DUMMY_CYCLES_READ_QUAD_DTR 8 + +#define MX25L512_BULK_ERASE_MAX_TIME 600000 +#define MX25L512_SECTOR_ERASE_MAX_TIME 2000 +#define MX25L512_SUBSECTOR_ERASE_MAX_TIME 800 + +/** + * @brief MX25L512 Commands + */ +/* Reset Operations */ +#define RESET_ENABLE_CMD 0x66 +#define RESET_MEMORY_CMD 0x99 + +/* Identification Operations */ +#define READ_ID_CMD 0x9F +#define MULTIPLE_IO_READ_ID_CMD 0xAF +#define READ_SERIAL_FLASH_DISCO_PARAM_CMD 0x5A + +/* Read Operations */ +#define READ_CMD 0x03 +#define READ_4_BYTE_ADDR_CMD 0x13 + +#define FAST_READ_CMD 0x0B +#define FAST_READ_DTR_CMD 0x0D +#define FAST_READ_4_BYTE_ADDR_CMD 0x0C + +#define DUAL_OUT_FAST_READ_CMD 0x3B +#define DUAL_OUT_FAST_READ_4_BYTE_ADDR_CMD 0x3C + +#define DUAL_INOUT_FAST_READ_CMD 0xBB +#define DUAL_INOUT_FAST_READ_DTR_CMD 0xBD +#define DUAL_INOUT_FAST_READ_4_BYTE_ADDR_CMD 0xBC + +#define QUAD_OUT_FAST_READ_CMD 0x6B +#define QUAD_OUT_FAST_READ_4_BYTE_ADDR_CMD 0x6C + +#define QUAD_INOUT_FAST_READ_CMD 0xEB +#define QUAD_INOUT_FAST_READ_DTR_CMD 0xED +#define QSPI_READ_4_BYTE_ADDR_CMD 0xEC + +/* Write Operations */ +#define WRITE_ENABLE_CMD 0x06 +#define WRITE_DISABLE_CMD 0x04 + +/* Register Operations */ +#define READ_STATUS_REG_CMD 0x05 +#define READ_CFG_REG_CMD 0x15 +#define WRITE_STATUS_CFG_REG_CMD 0x01 + +#define READ_LOCK_REG_CMD 0x2D +#define WRITE_LOCK_REG_CMD 0x2C + +#define READ_EXT_ADDR_REG_CMD 0xC8 +#define WRITE_EXT_ADDR_REG_CMD 0xC5 + +/* Program Operations */ +#define PAGE_PROG_CMD 0x02 +#define QSPI_PAGE_PROG_4_BYTE_ADDR_CMD 0x12 + +#define QUAD_IN_FAST_PROG_CMD 0x38 +#define EXT_QUAD_IN_FAST_PROG_CMD 0x38 +#define QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD 0x3E + +/* Erase Operations */ +#define SUBSECTOR_ERASE_CMD 0x20 +#define SUBSECTOR_ERASE_4_BYTE_ADDR_CMD 0x21 + +#define SECTOR_ERASE_CMD 0xD8 +#define SECTOR_ERASE_4_BYTE_ADDR_CMD 0xDC + +#define BULK_ERASE_CMD 0xC7 + +#define PROG_ERASE_RESUME_CMD 0x30 +#define PROG_ERASE_SUSPEND_CMD 0xB0 + +/* 4-byte Address Mode Operations */ +#define ENTER_4_BYTE_ADDR_MODE_CMD 0xB7 +#define EXIT_4_BYTE_ADDR_MODE_CMD 0xE9 + +/* Quad Operations */ +#define ENTER_QUAD_CMD 0x35 +#define EXIT_QUAD_CMD 0xF5 + +/* Added for compatibility */ +#define QPI_READ_4_BYTE_ADDR_CMD QSPI_READ_4_BYTE_ADDR_CMD +#define QPI_PAGE_PROG_4_BYTE_ADDR_CMD QSPI_PAGE_PROG_4_BYTE_ADDR_CMD + +/** + * @brief MX25L512 Registers + */ +/* Status Register */ +#define MX25L512_SR_WIP ((uint8_t)0x01) /*!< Write in progress */ +#define MX25L512_SR_WREN ((uint8_t)0x02) /*!< Write enable latch */ +#define MX25L512_SR_BLOCKPR ((uint8_t)0x5C) /*!< Block protected against program and erase operations */ +#define MX25L512_SR_PRBOTTOM ((uint8_t)0x20) /*!< Protected memory area defined by BLOCKPR starts from top or bottom */ +#define MX25L512_SR_QUADEN ((uint8_t)0x40) /*!< Quad IO mode enabled if =1 */ +#define MX25L512_SR_SRWREN ((uint8_t)0x80) /*!< Status register write enable/disable */ + +/* Configuration Register */ +#define MX25L512_CR_ODS ((uint8_t)0x07) /*!< Output driver strength */ +#define MX25L512_CR_ODS_30 ((uint8_t)0x07) /*!< Output driver strength 30 ohms (default)*/ +#define MX25L512_CR_ODS_15 ((uint8_t)0x06) /*!< Output driver strength 15 ohms */ +#define MX25L512_CR_ODS_20 ((uint8_t)0x05) /*!< Output driver strength 20 ohms */ +#define MX25L512_CR_ODS_45 ((uint8_t)0x03) /*!< Output driver strength 45 ohms */ +#define MX25L512_CR_ODS_60 ((uint8_t)0x02) /*!< Output driver strength 60 ohms */ +#define MX25L512_CR_ODS_90 ((uint8_t)0x01) /*!< Output driver strength 90 ohms */ +#define MX25L512_CR_TB ((uint8_t)0x08) /*!< Top/Bottom bit used to configure the block protect area */ +#define MX25L512_CR_PBE ((uint8_t)0x10) /*!< Preamble Bit Enable */ +#define MX25L512_CR_4BYTE ((uint8_t)0x20) /*!< 3-bytes or 4-bytes addressing */ +#define MX25L512_CR_NB_DUMMY ((uint8_t)0xC0) /*!< Number of dummy clock cycles */ + +#define MX25L512_MANUFACTURER_ID ((uint8_t)0xC2) +#define MX25L512_DEVICE_ID_MEM_TYPE ((uint8_t)0x20) +#define MX25L512_DEVICE_ID_MEM_CAPACITY ((uint8_t)0x1A) +#define MX25L512_UNIQUE_ID_DATA_LENGTH ((uint8_t)0x10) + +/** + * @} + */ + +/** @defgroup MX25L512_Exported_Functions + * @{ + */ +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __MX25L512_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/n25q128a/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/n25q128a/Release_Notes.html new file mode 100644 index 00000000..379ba680 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/n25q128a/Release_Notes.html @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + Release Notes for STM32 BSP Components Drivers + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for N25Q128A Component Driver

+

Copyright +2015 STMicroelectronics

+

+
+

 

+ + + + + + +

Update History

V1.0.1 +/ 25-August-2017

+ +

Main +Changes

+ + + + + + + + + + +
  • Update comments to be used for PDSC generation

V1.0.0 +/ 29-May-2015

+

Main +Changes

+ + + + + + + + + +
  • First official +release of N25Q128A QuadSPI Flash Component driver

License

+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+
For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32
+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/n25q128a/n25q128a.h b/src/port_stm32f7/common/bsp_drivers/Components/n25q128a/n25q128a.h new file mode 100644 index 00000000..977fa795 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/n25q128a/n25q128a.h @@ -0,0 +1,217 @@ +/** + ****************************************************************************** + * @file n25q128a.h + * @author MCD Application Team + * @brief This file contains all the description of the N25Q128A QSPI memory. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __N25Q128A_H +#define __N25Q128A_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup n25q128a + * @{ + */ + +/** @defgroup N25Q128A_Exported_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup N25Q128A_Exported_Constants + * @{ + */ + +/** + * @brief N25Q128A Configuration + */ +#define N25Q128A_FLASH_SIZE 0x1000000 /* 128 MBits => 16MBytes */ +#define N25Q128A_SECTOR_SIZE 0x10000 /* 256 sectors of 64KBytes */ +#define N25Q128A_SUBSECTOR_SIZE 0x1000 /* 4096 subsectors of 4kBytes */ +#define N25Q128A_PAGE_SIZE 0x100 /* 65536 pages of 256 bytes */ + +#define N25Q128A_DUMMY_CYCLES_READ 8 +#define N25Q128A_DUMMY_CYCLES_READ_QUAD 10 + +#define N25Q128A_BULK_ERASE_MAX_TIME 250000 +#define N25Q128A_SECTOR_ERASE_MAX_TIME 3000 +#define N25Q128A_SUBSECTOR_ERASE_MAX_TIME 800 + +/** + * @brief N25Q128A Commands + */ +/* Reset Operations */ +#define RESET_ENABLE_CMD 0x66 +#define RESET_MEMORY_CMD 0x99 + +/* Identification Operations */ +#define READ_ID_CMD 0x9E +#define READ_ID_CMD2 0x9F +#define MULTIPLE_IO_READ_ID_CMD 0xAF +#define READ_SERIAL_FLASH_DISCO_PARAM_CMD 0x5A + +/* Read Operations */ +#define READ_CMD 0x03 +#define FAST_READ_CMD 0x0B +#define DUAL_OUT_FAST_READ_CMD 0x3B +#define DUAL_INOUT_FAST_READ_CMD 0xBB +#define QUAD_OUT_FAST_READ_CMD 0x6B +#define QUAD_INOUT_FAST_READ_CMD 0xEB + +/* Write Operations */ +#define WRITE_ENABLE_CMD 0x06 +#define WRITE_DISABLE_CMD 0x04 + +/* Register Operations */ +#define READ_STATUS_REG_CMD 0x05 +#define WRITE_STATUS_REG_CMD 0x01 + +#define READ_LOCK_REG_CMD 0xE8 +#define WRITE_LOCK_REG_CMD 0xE5 + +#define READ_FLAG_STATUS_REG_CMD 0x70 +#define CLEAR_FLAG_STATUS_REG_CMD 0x50 + +#define READ_NONVOL_CFG_REG_CMD 0xB5 +#define WRITE_NONVOL_CFG_REG_CMD 0xB1 + +#define READ_VOL_CFG_REG_CMD 0x85 +#define WRITE_VOL_CFG_REG_CMD 0x81 + +#define READ_ENHANCED_VOL_CFG_REG_CMD 0x65 +#define WRITE_ENHANCED_VOL_CFG_REG_CMD 0x61 + +/* Program Operations */ +#define PAGE_PROG_CMD 0x02 +#define DUAL_IN_FAST_PROG_CMD 0xA2 +#define EXT_DUAL_IN_FAST_PROG_CMD 0xD2 +#define QUAD_IN_FAST_PROG_CMD 0x32 +#define EXT_QUAD_IN_FAST_PROG_CMD 0x12 + +/* Erase Operations */ +#define SUBSECTOR_ERASE_CMD 0x20 +#define SECTOR_ERASE_CMD 0xD8 +#define BULK_ERASE_CMD 0xC7 + +#define PROG_ERASE_RESUME_CMD 0x7A +#define PROG_ERASE_SUSPEND_CMD 0x75 + +/* One-Time Programmable Operations */ +#define READ_OTP_ARRAY_CMD 0x4B +#define PROG_OTP_ARRAY_CMD 0x42 + +/** + * @brief N25Q128A Registers + */ +/* Status Register */ +#define N25Q128A_SR_WIP ((uint8_t)0x01) /*!< Write in progress */ +#define N25Q128A_SR_WREN ((uint8_t)0x02) /*!< Write enable latch */ +#define N25Q128A_SR_BLOCKPR ((uint8_t)0x5C) /*!< Block protected against program and erase operations */ +#define N25Q128A_SR_PRBOTTOM ((uint8_t)0x20) /*!< Protected memory area defined by BLOCKPR starts from top or bottom */ +#define N25Q128A_SR_SRWREN ((uint8_t)0x80) /*!< Status register write enable/disable */ + +/* Nonvolatile Configuration Register */ +#define N25Q128A_NVCR_LOCK ((uint16_t)0x0001) /*!< Lock nonvolatile configuration register */ +#define N25Q128A_NVCR_DUAL ((uint16_t)0x0004) /*!< Dual I/O protocol */ +#define N25Q128A_NVCR_QUAB ((uint16_t)0x0008) /*!< Quad I/O protocol */ +#define N25Q128A_NVCR_RH ((uint16_t)0x0010) /*!< Reset/hold */ +#define N25Q128A_NVCR_ODS ((uint16_t)0x01C0) /*!< Output driver strength */ +#define N25Q128A_NVCR_XIP ((uint16_t)0x0E00) /*!< XIP mode at power-on reset */ +#define N25Q128A_NVCR_NB_DUMMY ((uint16_t)0xF000) /*!< Number of dummy clock cycles */ + +/* Volatile Configuration Register */ +#define N25Q128A_VCR_WRAP ((uint8_t)0x03) /*!< Wrap */ +#define N25Q128A_VCR_XIP ((uint8_t)0x08) /*!< XIP */ +#define N25Q128A_VCR_NB_DUMMY ((uint8_t)0xF0) /*!< Number of dummy clock cycles */ + +/* Enhanced Volatile Configuration Register */ +#define N25Q128A_EVCR_ODS ((uint8_t)0x07) /*!< Output driver strength */ +#define N25Q128A_EVCR_VPPA ((uint8_t)0x08) /*!< Vpp accelerator */ +#define N25Q128A_EVCR_RH ((uint8_t)0x10) /*!< Reset/hold */ +#define N25Q128A_EVCR_DUAL ((uint8_t)0x40) /*!< Dual I/O protocol */ +#define N25Q128A_EVCR_QUAD ((uint8_t)0x80) /*!< Quad I/O protocol */ + +/* Flag Status Register */ +#define N25Q128A_FSR_PRERR ((uint8_t)0x02) /*!< Protection error */ +#define N25Q128A_FSR_PGSUS ((uint8_t)0x04) /*!< Program operation suspended */ +#define N25Q128A_FSR_VPPERR ((uint8_t)0x08) /*!< Invalid voltage during program or erase */ +#define N25Q128A_FSR_PGERR ((uint8_t)0x10) /*!< Program error */ +#define N25Q128A_FSR_ERERR ((uint8_t)0x20) /*!< Erase error */ +#define N25Q128A_FSR_ERSUS ((uint8_t)0x40) /*!< Erase operation suspended */ +#define N25Q128A_FSR_READY ((uint8_t)0x80) /*!< Ready or command in progress */ + +/** + * @} + */ + +/** @defgroup N25Q128A_Exported_Functions + * @{ + */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __N25Q128A_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/n25q512a/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/n25q512a/Release_Notes.html new file mode 100644 index 00000000..bc863ad5 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/n25q512a/Release_Notes.html @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + Release Notes for STM32 BSP Components Drivers + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for N25Q512A Component Driver

+

Copyright +2017 STMicroelectronics

+

+
+

 

+ + + + + + +

Update History

+

V1.0.1 +/ 07-April-2017

+ +

Main +Changes

+ + + + + + + + + + +
    +
  • Update comments to be used for PDSC generation
  • +
+

V1.0.0 +/ 28-April-2015

+ +

Main +Changes

+ + + + + + + + + +
  • First official +release N25Q512A QSPI component driver
    +

License

+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+
For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32
+

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/n25q512a/n25q512a.h b/src/port_stm32f7/common/bsp_drivers/Components/n25q512a/n25q512a.h new file mode 100644 index 00000000..ec7006e8 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/n25q512a/n25q512a.h @@ -0,0 +1,259 @@ +/** + ****************************************************************************** + * @file n25q512a.h + * @author MCD Application Team + * @brief This file contains all the description of the N25Q512A QSPI memory. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __N25Q512A_H +#define __N25Q512A_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup n25q512a + * @{ + */ + +/** @defgroup N25Q512A_Exported_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup N25Q512A_Exported_Constants + * @{ + */ + +/** + * @brief N25Q512A Configuration + */ +#define N25Q512A_FLASH_SIZE 0x4000000 /* 512 MBits => 64MBytes */ +#define N25Q512A_SECTOR_SIZE 0x10000 /* 1024 sectors of 64KBytes */ +#define N25Q512A_SUBSECTOR_SIZE 0x1000 /* 16384 subsectors of 4kBytes */ +#define N25Q512A_PAGE_SIZE 0x100 /* 262144 pages of 256 bytes */ + +#define N25Q512A_DUMMY_CYCLES_READ 8 +#define N25Q512A_DUMMY_CYCLES_READ_QUAD 10 +#define N25Q512A_DUMMY_CYCLES_READ_DTR 6 +#define N25Q512A_DUMMY_CYCLES_READ_QUAD_DTR 8 + +#define N25Q512A_BULK_ERASE_MAX_TIME 480000 +#define N25Q512A_SECTOR_ERASE_MAX_TIME 3000 +#define N25Q512A_SUBSECTOR_ERASE_MAX_TIME 800 + +/** + * @brief N25Q512A Commands + */ +/* Reset Operations */ +#define RESET_ENABLE_CMD 0x66 +#define RESET_MEMORY_CMD 0x99 + +/* Identification Operations */ +#define READ_ID_CMD 0x9E +#define READ_ID_CMD2 0x9F +#define MULTIPLE_IO_READ_ID_CMD 0xAF +#define READ_SERIAL_FLASH_DISCO_PARAM_CMD 0x5A + +/* Read Operations */ +#define READ_CMD 0x03 +#define READ_4_BYTE_ADDR_CMD 0x13 + +#define FAST_READ_CMD 0x0B +#define FAST_READ_DTR_CMD 0x0D +#define FAST_READ_4_BYTE_ADDR_CMD 0x0C + +#define DUAL_OUT_FAST_READ_CMD 0x3B +#define DUAL_OUT_FAST_READ_DTR_CMD 0x3D +#define DUAL_OUT_FAST_READ_4_BYTE_ADDR_CMD 0x3C + +#define DUAL_INOUT_FAST_READ_CMD 0xBB +#define DUAL_INOUT_FAST_READ_DTR_CMD 0xBD +#define DUAL_INOUT_FAST_READ_4_BYTE_ADDR_CMD 0xBC + +#define QUAD_OUT_FAST_READ_CMD 0x6B +#define QUAD_OUT_FAST_READ_DTR_CMD 0x6D +#define QUAD_OUT_FAST_READ_4_BYTE_ADDR_CMD 0x6C + +#define QUAD_INOUT_FAST_READ_CMD 0xEB +#define QUAD_INOUT_FAST_READ_DTR_CMD 0xED +#define QUAD_INOUT_FAST_READ_4_BYTE_ADDR_CMD 0xEC + +/* Write Operations */ +#define WRITE_ENABLE_CMD 0x06 +#define WRITE_DISABLE_CMD 0x04 + +/* Register Operations */ +#define READ_STATUS_REG_CMD 0x05 +#define WRITE_STATUS_REG_CMD 0x01 + +#define READ_LOCK_REG_CMD 0xE8 +#define WRITE_LOCK_REG_CMD 0xE5 + +#define READ_FLAG_STATUS_REG_CMD 0x70 +#define CLEAR_FLAG_STATUS_REG_CMD 0x50 + +#define READ_NONVOL_CFG_REG_CMD 0xB5 +#define WRITE_NONVOL_CFG_REG_CMD 0xB1 + +#define READ_VOL_CFG_REG_CMD 0x85 +#define WRITE_VOL_CFG_REG_CMD 0x81 + +#define READ_ENHANCED_VOL_CFG_REG_CMD 0x65 +#define WRITE_ENHANCED_VOL_CFG_REG_CMD 0x61 + +#define READ_EXT_ADDR_REG_CMD 0xC8 +#define WRITE_EXT_ADDR_REG_CMD 0xC5 + +/* Program Operations */ +#define PAGE_PROG_CMD 0x02 +#define PAGE_PROG_4_BYTE_ADDR_CMD 0x12 + +#define DUAL_IN_FAST_PROG_CMD 0xA2 +#define EXT_DUAL_IN_FAST_PROG_CMD 0xD2 + +#define QUAD_IN_FAST_PROG_CMD 0x32 +#define EXT_QUAD_IN_FAST_PROG_CMD 0x12 /*0x38*/ +#define QUAD_IN_FAST_PROG_4_BYTE_ADDR_CMD 0x34 + +/* Erase Operations */ +#define SUBSECTOR_ERASE_CMD 0x20 +#define SUBSECTOR_ERASE_4_BYTE_ADDR_CMD 0x21 + +#define SECTOR_ERASE_CMD 0xD8 +#define SECTOR_ERASE_4_BYTE_ADDR_CMD 0xDC + +#define BULK_ERASE_CMD 0xC7 + +#define PROG_ERASE_RESUME_CMD 0x7A +#define PROG_ERASE_SUSPEND_CMD 0x75 + +/* One-Time Programmable Operations */ +#define READ_OTP_ARRAY_CMD 0x4B +#define PROG_OTP_ARRAY_CMD 0x42 + +/* 4-byte Address Mode Operations */ +#define ENTER_4_BYTE_ADDR_MODE_CMD 0xB7 +#define EXIT_4_BYTE_ADDR_MODE_CMD 0xE9 + +/* Quad Operations */ +#define ENTER_QUAD_CMD 0x35 +#define EXIT_QUAD_CMD 0xF5 + +/** + * @brief N25Q512A Registers + */ +/* Status Register */ +#define N25Q512A_SR_WIP ((uint8_t)0x01) /*!< Write in progress */ +#define N25Q512A_SR_WREN ((uint8_t)0x02) /*!< Write enable latch */ +#define N25Q512A_SR_BLOCKPR ((uint8_t)0x5C) /*!< Block protected against program and erase operations */ +#define N25Q512A_SR_PRBOTTOM ((uint8_t)0x20) /*!< Protected memory area defined by BLOCKPR starts from top or bottom */ +#define N25Q512A_SR_SRWREN ((uint8_t)0x80) /*!< Status register write enable/disable */ + +/* Non volatile Configuration Register */ +#define N25Q512A_NVCR_NBADDR ((uint16_t)0x0001) /*!< 3-bytes or 4-bytes addressing */ +#define N25Q512A_NVCR_SEGMENT ((uint16_t)0x0002) /*!< Upper or lower 128Mb segment selected by default */ +#define N25Q512A_NVCR_DUAL ((uint16_t)0x0004) /*!< Dual I/O protocol */ +#define N25Q512A_NVCR_QUAB ((uint16_t)0x0008) /*!< Quad I/O protocol */ +#define N25Q512A_NVCR_RH ((uint16_t)0x0010) /*!< Reset/hold */ +#define N25Q512A_NVCR_ODS ((uint16_t)0x01C0) /*!< Output driver strength */ +#define N25Q512A_NVCR_XIP ((uint16_t)0x0E00) /*!< XIP mode at power-on reset */ +#define N25Q512A_NVCR_NB_DUMMY ((uint16_t)0xF000) /*!< Number of dummy clock cycles */ + +/* Volatile Configuration Register */ +#define N25Q512A_VCR_WRAP ((uint8_t)0x03) /*!< Wrap */ +#define N25Q512A_VCR_XIP ((uint8_t)0x08) /*!< XIP */ +#define N25Q512A_VCR_NB_DUMMY ((uint8_t)0xF0) /*!< Number of dummy clock cycles */ + +/* Extended Address Register */ +#define N25Q512A_EAR_A24 ((uint8_t)0x01) /*!< Select the lower or upper 128Mb segment */ + +/* Enhanced Volatile Configuration Register */ +#define N25Q512A_EVCR_ODS ((uint8_t)0x07) /*!< Output driver strength */ +#define N25Q512A_EVCR_VPPA ((uint8_t)0x08) /*!< Vpp accelerator */ +#define N25Q512A_EVCR_RH ((uint8_t)0x10) /*!< Reset/hold */ +#define N25Q512A_EVCR_DUAL ((uint8_t)0x40) /*!< Dual I/O protocol */ +#define N25Q512A_EVCR_QUAD ((uint8_t)0x80) /*!< Quad I/O protocol */ + +/* Flag Status Register */ +#define N25Q512A_FSR_NBADDR ((uint8_t)0x01) /*!< 3-bytes or 4-bytes addressing */ +#define N25Q512A_FSR_PRERR ((uint8_t)0x02) /*!< Protection error */ +#define N25Q512A_FSR_PGSUS ((uint8_t)0x04) /*!< Program operation suspended */ +#define N25Q512A_FSR_VPPERR ((uint8_t)0x08) /*!< Invalid voltage during program or erase */ +#define N25Q512A_FSR_PGERR ((uint8_t)0x10) /*!< Program error */ +#define N25Q512A_FSR_ERERR ((uint8_t)0x20) /*!< Erase error */ +#define N25Q512A_FSR_ERSUS ((uint8_t)0x40) /*!< Erase operation suspended */ +#define N25Q512A_FSR_READY ((uint8_t)0x80) /*!< Ready or command in progress */ + +/** + * @} + */ + +/** @defgroup N25Q512A_Exported_Functions + * @{ + */ +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __N25Q512A_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/otm8009a/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/otm8009a/Release_Notes.html new file mode 100644 index 00000000..8ba0bea2 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/otm8009a/Release_Notes.html @@ -0,0 +1,254 @@ + + + + +Release Notes for OTM8009A BSP Components Drivers + + + + + + + + + + +
+ +

 

+ +
+ + + + + +
+ + + + + + + +
+

Back to Release page

+
+

Release Notes for OTM8009A Component + Driver

+

Copyright + 2017 STMicroelectronics

+

+
+

 

+ + + + + + + +
+

Update + History

+

V1.0.5 / + 12-February-2021

+

Main Changes

+
    +
  • Set the PWM + backlight frequency to over 22KHz to avoid audible noise.
  • +
+

V1.0.4 / 23-November-2020 +

+

Main Changes

+
    +
  • Update + otm8009a.h to support ARM compiler Keil V6
  • +
+

V1.0.3 / + 07-April-2017

+

Main Changes

+
    +
  • Update + comments to be used for PDSC generation
  • +
+

V1.0.2 / + 27-January-2017

+

Main Changes

+
    +
  • Update DSI + controller timings
  • +
  • CABC LEDPWM frequency + adjusted to 19,5kHz
  • +
+

V1.0.1 / + 04-August-2016

+

Main Changes

+
    +
  • Update DSI + controller timings
  • +
+

V1.0.0 / + 03-August-2015

+

Main Changes

+
    +
  • First + official release of OTM8009A LCD component driver
  • +
+

License

+

Redistribution and use in source and + binary forms, with or without modification, are permitted provided that the + following conditions are met:

+
    +
  1. Redistributions + of source code must retain the above copyright notice, this list of + conditions and the following disclaimer.
  2. +
  3. Redistributions + in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution.
  4. +
  5. Neither the + name of STMicroelectronics nor the names of its contributors may be + used to endorse or promote products derived
  6. +
+

       from + this software without specific prior written permission.
+
+
THIS + SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+

 

+
+
+
+
+

For complete documentation on STM32 Microcontrollers + visit www.st.com/STM32

+
+
+

+
+ +
+ +

 

+ +
+ + + + diff --git a/src/port_stm32f7/common/bsp_drivers/Components/otm8009a/otm8009a.c b/src/port_stm32f7/common/bsp_drivers/Components/otm8009a/otm8009a.c new file mode 100644 index 00000000..f2183d2d --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/otm8009a/otm8009a.c @@ -0,0 +1,452 @@ +/** + ****************************************************************************** + * @file otm8009a.c + * @author MCD Application Team + * @brief This file provides the LCD Driver for KoD KM-040TMP-02-0621 (WVGA) + * DSI LCD Display OTM8009A. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "otm8009a.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @defgroup OTM8009A OTM8009A + * @brief This file provides a set of functions needed to drive the + * otm8009a IC display driver. + * @{ + */ + +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private constants ---------------------------------------------------------*/ +/** @defgroup OTM8009A_Private_Constants OTM8009A Private Constants + * @{ + */ + +/* + * @brief Constant tables of register settings used to transmit DSI + * command packets as power up initialization sequence of the KoD LCD (OTM8009A LCD Driver) + */ +const uint8_t lcdRegData1[] = {0x80,0x09,0x01,0xFF}; +const uint8_t lcdRegData2[] = {0x80,0x09,0xFF}; +const uint8_t lcdRegData3[] = {0x00,0x09,0x0F,0x0E,0x07,0x10,0x0B,0x0A,0x04,0x07,0x0B,0x08,0x0F,0x10,0x0A,0x01,0xE1}; +const uint8_t lcdRegData4[] = {0x00,0x09,0x0F,0x0E,0x07,0x10,0x0B,0x0A,0x04,0x07,0x0B,0x08,0x0F,0x10,0x0A,0x01,0xE2}; +const uint8_t lcdRegData5[] = {0x79,0x79,0xD8}; +const uint8_t lcdRegData6[] = {0x00,0x01,0xB3}; +const uint8_t lcdRegData7[] = {0x85,0x01,0x00,0x84,0x01,0x00,0xCE}; +const uint8_t lcdRegData8[] = {0x18,0x04,0x03,0x39,0x00,0x00,0x00,0x18,0x03,0x03,0x3A,0x00,0x00,0x00,0xCE}; +const uint8_t lcdRegData9[] = {0x18,0x02,0x03,0x3B,0x00,0x00,0x00,0x18,0x01,0x03,0x3C,0x00,0x00,0x00,0xCE}; +const uint8_t lcdRegData10[] = {0x01,0x01,0x20,0x20,0x00,0x00,0x01,0x02,0x00,0x00,0xCF}; +const uint8_t lcdRegData11[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCB}; +const uint8_t lcdRegData12[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCB}; +const uint8_t lcdRegData13[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCB}; +const uint8_t lcdRegData14[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCB}; +const uint8_t lcdRegData15[] = {0x00,0x04,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCB}; +const uint8_t lcdRegData16[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0xCB}; +const uint8_t lcdRegData17[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCB}; +const uint8_t lcdRegData18[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xCB}; +const uint8_t lcdRegData19[] = {0x00,0x26,0x09,0x0B,0x01,0x25,0x00,0x00,0x00,0x00,0xCC}; +const uint8_t lcdRegData20[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x26,0x0A,0x0C,0x02,0xCC}; +const uint8_t lcdRegData21[] = {0x25,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCC}; +const uint8_t lcdRegData22[] = {0x00,0x25,0x0C,0x0A,0x02,0x26,0x00,0x00,0x00,0x00,0xCC}; +const uint8_t lcdRegData23[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x25,0x0B,0x09,0x01,0xCC}; +const uint8_t lcdRegData24[] = {0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCC}; +const uint8_t lcdRegData25[] = {0xFF,0xFF,0xFF,0xFF}; +/* + * CASET value (Column Address Set) : X direction LCD GRAM boundaries + * depending on LCD orientation mode and PASET value (Page Address Set) : Y direction + * LCD GRAM boundaries depending on LCD orientation mode + * XS[15:0] = 0x000 = 0, XE[15:0] = 0x31F = 799 for landscape mode : apply to CASET + * YS[15:0] = 0x000 = 0, YE[15:0] = 0x31F = 799 for portrait mode : : apply to PASET + */ +const uint8_t lcdRegData27[] = {0x00, 0x00, 0x03, 0x1F, OTM8009A_CMD_CASET}; +/* + * XS[15:0] = 0x000 = 0, XE[15:0] = 0x1DF = 479 for portrait mode : apply to CASET + * YS[15:0] = 0x000 = 0, YE[15:0] = 0x1DF = 479 for landscape mode : apply to PASET + */ +const uint8_t lcdRegData28[] = {0x00, 0x00, 0x01, 0xDF, OTM8009A_CMD_PASET}; + + +const uint8_t ShortRegData1[] = {OTM8009A_CMD_NOP, 0x00}; +const uint8_t ShortRegData2[] = {OTM8009A_CMD_NOP, 0x80}; +const uint8_t ShortRegData3[] = {0xC4, 0x30}; +const uint8_t ShortRegData4[] = {OTM8009A_CMD_NOP, 0x8A}; +const uint8_t ShortRegData5[] = {0xC4, 0x40}; +const uint8_t ShortRegData6[] = {OTM8009A_CMD_NOP, 0xB1}; +const uint8_t ShortRegData7[] = {0xC5, 0xA9}; +const uint8_t ShortRegData8[] = {OTM8009A_CMD_NOP, 0x91}; +const uint8_t ShortRegData9[] = {0xC5, 0x34}; +const uint8_t ShortRegData10[] = {OTM8009A_CMD_NOP, 0xB4}; +const uint8_t ShortRegData11[] = {0xC0, 0x50}; +const uint8_t ShortRegData12[] = {0xD9, 0x4E}; +const uint8_t ShortRegData13[] = {OTM8009A_CMD_NOP, 0x81}; +const uint8_t ShortRegData14[] = {0xC1, 0x66}; +const uint8_t ShortRegData15[] = {OTM8009A_CMD_NOP, 0xA1}; +const uint8_t ShortRegData16[] = {0xC1, 0x08}; +const uint8_t ShortRegData17[] = {OTM8009A_CMD_NOP, 0x92}; +const uint8_t ShortRegData18[] = {0xC5, 0x01}; +const uint8_t ShortRegData19[] = {OTM8009A_CMD_NOP, 0x95}; +const uint8_t ShortRegData20[] = {OTM8009A_CMD_NOP, 0x94}; +const uint8_t ShortRegData21[] = {0xC5, 0x33}; +const uint8_t ShortRegData22[] = {OTM8009A_CMD_NOP, 0xA3}; +const uint8_t ShortRegData23[] = {0xC0, 0x1B}; +const uint8_t ShortRegData24[] = {OTM8009A_CMD_NOP, 0x82}; +const uint8_t ShortRegData25[] = {0xC5, 0x83}; +const uint8_t ShortRegData26[] = {0xC4, 0x83}; +const uint8_t ShortRegData27[] = {0xC1, 0x0E}; +const uint8_t ShortRegData28[] = {OTM8009A_CMD_NOP, 0xA6}; +const uint8_t ShortRegData29[] = {OTM8009A_CMD_NOP, 0xA0}; +const uint8_t ShortRegData30[] = {OTM8009A_CMD_NOP, 0xB0}; +const uint8_t ShortRegData31[] = {OTM8009A_CMD_NOP, 0xC0}; +const uint8_t ShortRegData32[] = {OTM8009A_CMD_NOP, 0xD0}; +const uint8_t ShortRegData33[] = {OTM8009A_CMD_NOP, 0x90}; +const uint8_t ShortRegData34[] = {OTM8009A_CMD_NOP, 0xE0}; +const uint8_t ShortRegData35[] = {OTM8009A_CMD_NOP, 0xF0}; +const uint8_t ShortRegData36[] = {OTM8009A_CMD_SLPOUT, 0x00}; +const uint8_t ShortRegData37[] = {OTM8009A_CMD_COLMOD, OTM8009A_COLMOD_RGB565}; +const uint8_t ShortRegData38[] = {OTM8009A_CMD_COLMOD, OTM8009A_COLMOD_RGB888}; +const uint8_t ShortRegData39[] = {OTM8009A_CMD_MADCTR, OTM8009A_MADCTR_MODE_LANDSCAPE}; +const uint8_t ShortRegData40[] = {OTM8009A_CMD_WRDISBV, 0x7F}; +const uint8_t ShortRegData41[] = {OTM8009A_CMD_WRCTRLD, 0x2C}; +const uint8_t ShortRegData42[] = {OTM8009A_CMD_WRCABC, 0x02}; +const uint8_t ShortRegData43[] = {OTM8009A_CMD_WRCABCMB, 0xFF}; +const uint8_t ShortRegData44[] = {OTM8009A_CMD_DISPON, 0x00}; +const uint8_t ShortRegData45[] = {OTM8009A_CMD_RAMWR, 0x00}; +const uint8_t ShortRegData46[] = {0xCF, 0x00}; +const uint8_t ShortRegData47[] = {0xC5, 0x66}; +const uint8_t ShortRegData48[] = {OTM8009A_CMD_NOP, 0xB6}; +const uint8_t ShortRegData49[] = {0xF5, 0x06}; +const uint8_t ShortRegData50[] = {OTM8009A_CMD_NOP, 0xB1}; +const uint8_t ShortRegData51[] = {0xC6, 0x05}; +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ +/** @defgroup OTM8009A_Exported_Variables + * @{ + */ + +/** + * @} + */ + +/* Exported functions ---------------------------------------------------------*/ +/** @defgroup OTM8009A_Exported_Functions OTM8009A Exported Functions + * @{ + */ + +/** + * @brief DSI IO write short/long command. + * @note : Can be surcharged by application code implementation of the function. + */ +__weak void DSI_IO_WriteCmd(uint32_t NbrParams, uint8_t *pParams) +{ + /* NOTE : This function Should not be modified, when it is needed, + the DSI_IO_WriteCmd could be implemented in the user file + */ +} + +/** + * @brief Initializes the LCD KoD display part by communication in DSI mode in Video Mode + * with IC Display Driver OTM8009A (see IC Driver specification for more information). + * @param hdsi_eval : pointer on DSI configuration structure + * @param hdsivideo_handle : pointer on DSI video mode configuration structure + * @retval Status + */ +uint8_t OTM8009A_Init(uint32_t ColorCoding, uint32_t orientation) +{ + /* Enable CMD2 to access vendor specific commands */ + /* Enter in command 2 mode and set EXTC to enable address shift function (0x00) */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1); + DSI_IO_WriteCmd( 3, (uint8_t *)lcdRegData1); + + /* Enter ORISE Command 2 */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData2); /* Shift address to 0x80 */ + DSI_IO_WriteCmd( 2, (uint8_t *)lcdRegData2); + + ///////////////////////////////////////////////////////////////////// + /* SD_PCH_CTRL - 0xC480h - 129th parameter - Default 0x00 */ + /* Set SD_PT */ + /* -> Source output level during porch and non-display area to GND */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData2); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData3); + OTM8009A_IO_Delay(10); + /* Not documented */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData4); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData5); + OTM8009A_IO_Delay(10); + ///////////////////////////////////////////////////////////////////// + + /* PWR_CTRL4 - 0xC4B0h - 178th parameter - Default 0xA8 */ + /* Set gvdd_en_test */ + /* -> enable GVDD test mode !!! */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData6); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData7); + + /* PWR_CTRL2 - 0xC590h - 146th parameter - Default 0x79 */ + /* Set pump 4 vgh voltage */ + /* -> from 15.0v down to 13.0v */ + /* Set pump 5 vgh voltage */ + /* -> from -12.0v downto -9.0v */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData8); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData9); + + /* P_DRV_M - 0xC0B4h - 181th parameter - Default 0x00 */ + /* -> Column inversion */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData10); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData11); + + /* VCOMDC - 0xD900h - 1st parameter - Default 0x39h */ + /* VCOM Voltage settings */ + /* -> from -1.0000v downto -1.2625v */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData12); + + /* Oscillator adjustment for Idle/Normal mode (LPDT only) set to 65Hz (default is 60Hz) */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData13); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData14); + + /* Video mode internal */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData15); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData16); + + /* PWR_CTRL2 - 0xC590h - 147h parameter - Default 0x00 */ + /* Set pump 4&5 x6 */ + /* -> ONLY VALID when PUMP4_EN_ASDM_HV = "0" */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData17); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData18); + + /* PWR_CTRL2 - 0xC590h - 150th parameter - Default 0x33h */ + /* Change pump4 clock ratio */ + /* -> from 1 line to 1/2 line */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData19); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData9); + + /* GVDD/NGVDD settings */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1); + DSI_IO_WriteCmd( 2, (uint8_t *)lcdRegData5); + + /* PWR_CTRL2 - 0xC590h - 149th parameter - Default 0x33h */ + /* Rewrite the default value ! */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData20); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData21); + + /* Panel display timing Setting 3 */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData22); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData23); + + /* Power control 1 */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData24); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData25); + + /* Source driver precharge */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData13); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData26); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData15); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData27); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData28); + DSI_IO_WriteCmd( 2, (uint8_t *)lcdRegData6); + + /* GOAVST */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData2); + DSI_IO_WriteCmd( 6, (uint8_t *)lcdRegData7); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData29); + DSI_IO_WriteCmd( 14, (uint8_t *)lcdRegData8); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData30); + DSI_IO_WriteCmd( 14, (uint8_t *)lcdRegData9); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData31); + DSI_IO_WriteCmd( 10, (uint8_t *)lcdRegData10); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData32); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData46); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData2); + DSI_IO_WriteCmd( 10, (uint8_t *)lcdRegData11); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData33); + DSI_IO_WriteCmd( 15, (uint8_t *)lcdRegData12); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData29); + DSI_IO_WriteCmd( 15, (uint8_t *)lcdRegData13); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData30); + DSI_IO_WriteCmd( 10, (uint8_t *)lcdRegData14); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData31); + DSI_IO_WriteCmd( 15, (uint8_t *)lcdRegData15); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData32); + DSI_IO_WriteCmd( 15, (uint8_t *)lcdRegData16); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData34); + DSI_IO_WriteCmd( 10, (uint8_t *)lcdRegData17); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData35); + DSI_IO_WriteCmd( 10, (uint8_t *)lcdRegData18); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData2); + DSI_IO_WriteCmd( 10, (uint8_t *)lcdRegData19); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData33); + DSI_IO_WriteCmd( 15, (uint8_t *)lcdRegData20); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData29); + DSI_IO_WriteCmd( 15, (uint8_t *)lcdRegData21); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData30); + DSI_IO_WriteCmd( 10, (uint8_t *)lcdRegData22); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData31); + DSI_IO_WriteCmd( 15, (uint8_t *)lcdRegData23); + + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData32); + DSI_IO_WriteCmd( 15, (uint8_t *)lcdRegData24); + + ///////////////////////////////////////////////////////////////////////////// + /* PWR_CTRL1 - 0xc580h - 130th parameter - default 0x00 */ + /* Pump 1 min and max DM */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData13); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData47); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData48); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData49); + ///////////////////////////////////////////////////////////////////////////// + + /* CABC LEDPWM frequency adjusted to 22,7kHz */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData50); + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData51); + + /* Exit CMD2 mode */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1); + DSI_IO_WriteCmd( 3, (uint8_t *)lcdRegData25); + + /*************************************************************************** */ + /* Standard DCS Initialization TO KEEP CAN BE DONE IN HSDT */ + /*************************************************************************** */ + + /* NOP - goes back to DCS std command ? */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1); + + /* Gamma correction 2.2+ table (HSDT possible) */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1); + DSI_IO_WriteCmd( 16, (uint8_t *)lcdRegData3); + + /* Gamma correction 2.2- table (HSDT possible) */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1); + DSI_IO_WriteCmd( 16, (uint8_t *)lcdRegData4); + + /* Send Sleep Out command to display : no parameter */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData36); + + /* Wait for sleep out exit */ + OTM8009A_IO_Delay(120); + + switch(ColorCoding) + { + case OTM8009A_FORMAT_RBG565 : + /* Set Pixel color format to RGB565 */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData37); + break; + case OTM8009A_FORMAT_RGB888 : + /* Set Pixel color format to RGB888 */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData38); + break; + default : + break; + } + + /* Send command to configure display in landscape orientation mode. By default + the orientation mode is portrait */ + if(orientation == OTM8009A_ORIENTATION_LANDSCAPE) + { + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData39); + DSI_IO_WriteCmd( 4, (uint8_t *)lcdRegData27); + DSI_IO_WriteCmd( 4, (uint8_t *)lcdRegData28); + } + + /** CABC : Content Adaptive Backlight Control section start >> */ + /* Note : defaut is 0 (lowest Brightness), 0xFF is highest Brightness, try 0x7F : intermediate value */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData40); + + /* defaut is 0, try 0x2C - Brightness Control Block, Display Dimming & BackLight on */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData41); + + /* defaut is 0, try 0x02 - image Content based Adaptive Brightness [Still Picture] */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData42); + + /* defaut is 0 (lowest Brightness), 0xFF is highest Brightness */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData43); + + /** CABC : Content Adaptive Backlight Control section end << */ + + /* Send Command Display On */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData44); + + /* NOP command */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1); + + /* Send Command GRAM memory write (no parameters) : this initiates frame write via other DSI commands sent by */ + /* DSI host from LTDC incoming pixels in video mode */ + DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData45); + + return 0; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/otm8009a/otm8009a.h b/src/port_stm32f7/common/bsp_drivers/Components/otm8009a/otm8009a.h new file mode 100644 index 00000000..1e7b88f7 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/otm8009a/otm8009a.h @@ -0,0 +1,222 @@ +/** + ****************************************************************************** + * @file otm8009a.h + * @author MCD Application Team + * @brief This file contains all the constants parameters for the OTM8009A + * which is the LCD Driver for KoD KM-040TMP-02-0621 (WVGA) + * DSI LCD Display. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __OTM8009A_H +#define __OTM8009A_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup otm8009a + * @{ + */ + +/** @addtogroup OTM8009A_Exported_Variables + * @{ + */ + +#if defined ( __GNUC__ ) || (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)) /* GNU and ARM Compiler 6 compilers */ +#ifndef __weak +#define __weak __attribute__((weak)) +#endif /* __weak */ +#endif /* __GNUC__ || (__ARMCC_VERSION && (__ARMCC_VERSION >= 6010050)) */ + +/** + * @brief LCD_OrientationTypeDef + * Possible values of Display Orientation + */ +#define OTM8009A_ORIENTATION_PORTRAIT ((uint32_t)0x00) /* Portrait orientation choice of LCD screen */ +#define OTM8009A_ORIENTATION_LANDSCAPE ((uint32_t)0x01) /* Landscape orientation choice of LCD screen */ + +/** + * @brief Possible values of + * pixel data format (ie color coding) transmitted on DSI Data lane in DSI packets + */ +#define OTM8009A_FORMAT_RGB888 ((uint32_t)0x00) /* Pixel format chosen is RGB888 : 24 bpp */ +#define OTM8009A_FORMAT_RBG565 ((uint32_t)0x02) /* Pixel format chosen is RGB565 : 16 bpp */ + +/** + * @brief otm8009a_480x800 Size + */ + +/* Width and Height in Portrait mode */ +#define OTM8009A_480X800_WIDTH ((uint16_t)480) /* LCD PIXEL WIDTH */ +#define OTM8009A_480X800_HEIGHT ((uint16_t)800) /* LCD PIXEL HEIGHT */ + +/* Width and Height in Landscape mode */ +#define OTM8009A_800X480_WIDTH ((uint16_t)800) /* LCD PIXEL WIDTH */ +#define OTM8009A_800X480_HEIGHT ((uint16_t)480) /* LCD PIXEL HEIGHT */ + +/** + * @brief OTM8009A_480X800 Timing parameters for Portrait orientation mode + */ +#define OTM8009A_480X800_HSYNC ((uint16_t)2) /* Horizontal synchronization */ +#define OTM8009A_480X800_HBP ((uint16_t)34) /* Horizontal back porch */ +#define OTM8009A_480X800_HFP ((uint16_t)34) /* Horizontal front porch */ +#define OTM8009A_480X800_VSYNC ((uint16_t)1) /* Vertical synchronization */ +#define OTM8009A_480X800_VBP ((uint16_t)15) /* Vertical back porch */ +#define OTM8009A_480X800_VFP ((uint16_t)16) /* Vertical front porch */ + +/** + * @brief OTM8009A_800X480 Timing parameters for Landscape orientation mode + * Same values as for Portrait mode in fact. + */ +#define OTM8009A_800X480_HSYNC OTM8009A_480X800_VSYNC /* Horizontal synchronization */ +#define OTM8009A_800X480_HBP OTM8009A_480X800_VBP /* Horizontal back porch */ +#define OTM8009A_800X480_HFP OTM8009A_480X800_VFP /* Horizontal front porch */ +#define OTM8009A_800X480_VSYNC OTM8009A_480X800_HSYNC /* Vertical synchronization */ +#define OTM8009A_800X480_VBP OTM8009A_480X800_HBP /* Vertical back porch */ +#define OTM8009A_800X480_VFP OTM8009A_480X800_HFP /* Vertical front porch */ + + +/* List of OTM8009A used commands */ +/* Detailed in OTM8009A Data Sheet 'DATA_SHEET_OTM8009A_V0 92.pdf' */ +/* Version of 14 June 2012 */ +#define OTM8009A_CMD_NOP 0x00 /* NOP command */ +#define OTM8009A_CMD_SWRESET 0x01 /* Sw reset command */ +#define OTM8009A_CMD_RDDMADCTL 0x0B /* Read Display MADCTR command : read memory display access ctrl */ +#define OTM8009A_CMD_RDDCOLMOD 0x0C /* Read Display pixel format */ +#define OTM8009A_CMD_SLPIN 0x10 /* Sleep In command */ +#define OTM8009A_CMD_SLPOUT 0x11 /* Sleep Out command */ +#define OTM8009A_CMD_PTLON 0x12 /* Partial mode On command */ + +#define OTM8009A_CMD_DISPOFF 0x28 /* Display Off command */ +#define OTM8009A_CMD_DISPON 0x29 /* Display On command */ + +#define OTM8009A_CMD_CASET 0x2A /* Column address set command */ +#define OTM8009A_CMD_PASET 0x2B /* Page address set command */ + +#define OTM8009A_CMD_RAMWR 0x2C /* Memory (GRAM) write command */ +#define OTM8009A_CMD_RAMRD 0x2E /* Memory (GRAM) read command */ + +#define OTM8009A_CMD_PLTAR 0x30 /* Partial area command (4 parameters) */ + +#define OTM8009A_CMD_TEOFF 0x34 /* Tearing Effect Line Off command : command with no parameter */ + +#define OTM8009A_CMD_TEEON 0x35 /* Tearing Effect Line On command : command with 1 parameter 'TELOM' */ + +/* Parameter TELOM : Tearing Effect Line Output Mode : possible values */ +#define OTM8009A_TEEON_TELOM_VBLANKING_INFO_ONLY 0x00 +#define OTM8009A_TEEON_TELOM_VBLANKING_AND_HBLANKING_INFO 0x01 + +#define OTM8009A_CMD_MADCTR 0x36 /* Memory Access write control command */ + +/* Possible used values of MADCTR */ +#define OTM8009A_MADCTR_MODE_PORTRAIT 0x00 +#define OTM8009A_MADCTR_MODE_LANDSCAPE 0x60 /* MY = 0, MX = 1, MV = 1, ML = 0, RGB = 0 */ + +#define OTM8009A_CMD_IDMOFF 0x38 /* Idle mode Off command */ +#define OTM8009A_CMD_IDMON 0x39 /* Idle mode On command */ + +#define OTM8009A_CMD_COLMOD 0x3A /* Interface Pixel format command */ + +/* Possible values of COLMOD parameter corresponding to used pixel formats */ +#define OTM8009A_COLMOD_RGB565 0x55 +#define OTM8009A_COLMOD_RGB888 0x77 + +#define OTM8009A_CMD_RAMWRC 0x3C /* Memory write continue command */ +#define OTM8009A_CMD_RAMRDC 0x3E /* Memory read continue command */ + +#define OTM8009A_CMD_WRTESCN 0x44 /* Write Tearing Effect Scan line command */ +#define OTM8009A_CMD_RDSCNL 0x45 /* Read Tearing Effect Scan line command */ + +/* CABC Management : ie : Content Adaptive Back light Control in IC OTM8009a */ +#define OTM8009A_CMD_WRDISBV 0x51 /* Write Display Brightness command */ +#define OTM8009A_CMD_WRCTRLD 0x53 /* Write CTRL Display command */ +#define OTM8009A_CMD_WRCABC 0x55 /* Write Content Adaptive Brightness command */ +#define OTM8009A_CMD_WRCABCMB 0x5E /* Write CABC Minimum Brightness command */ + +/** + * @brief OTM8009A_480X800 frequency divider + */ +#define OTM8009A_480X800_FREQUENCY_DIVIDER 2 /* LCD Frequency divider */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ + +/** @defgroup OTM8009A_Exported_Macros OTM8009A Exported Macros + * @{ + */ + +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ + +/** @addtogroup OTM8009A_Exported_Functions + * @{ + */ +void DSI_IO_WriteCmd(uint32_t NbrParams, uint8_t *pParams); +uint8_t OTM8009A_Init(uint32_t ColorCoding, uint32_t orientation); +void OTM8009A_IO_Delay(uint32_t Delay); +/** + * @} + */ +#ifdef __cplusplus +} +#endif + +#endif /* __OTM8009A_480X800_H */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ov5640/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/ov5640/Release_Notes.html new file mode 100644 index 00000000..6f5e4e6d --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ov5640/Release_Notes.html @@ -0,0 +1,91 @@ + + + + + + + Release Notes for OV5640 Component Driver + + + + + +
+
+
+
+
+

Release Notes for OV5640 Component Driver

+

Copyright © 2019 STMicroelectronics
+

+ +
+
+
+

License

+This software component is licensed by ST under BSD 3-Clause license, the “Licenseâ€; You may not use this component except in compliance with the License. You may obtain a copy of the License at: +
+https://opensource.org/licenses/BSD-3-Clause +
+

Purpose

+

This driver provides a set of camera functions offered by OV5640 component

+
+
+

Update History

+
+ +
+

Main Changes

+
    +
  • Official Release of OV5640 Camera Component drivers in line with legacy BSP drivers development guidelines
    +
  • +
  • The component drivers are composed of +
      +
    • component core drivers files: ov5640.h/.c
    • +
  • +
+

Dependencies

+

This software release is compatible with:

+
    +
  • BSP Common version v5.1.2 or lower versions
  • +
+

Backward compatibility

+
    +
  • This software breaks the compatibility with previous version v1.0.0
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • First Official Release of OV5640 Camera Component drivers in line with STM32Cube BSP drivers development guidelines (UM2298)
    +
  • +
  • The component drivers are composed of +
      +
    • component core drivers files: ov5640.h/.c
    • +
    • component register drivers files: ov5640_regs.h/.c
    • +
  • +
+

Dependencies

+

This software release is compatible with:

+
    +
  • BSP Common v6.0.0 or above
  • +
+
+
+
+
+
+For complete documentation on STM32 Microcontrollers , visit: www.st.com +
+ + diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ov5640/_htmresc/mini-st.css b/src/port_stm32f7/common/bsp_drivers/Components/ov5640/_htmresc/mini-st.css new file mode 100644 index 00000000..71fbc14f --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ov5640/_htmresc/mini-st.css @@ -0,0 +1,1700 @@ +@charset "UTF-8"; +/* + Flavor name: Default (mini-default) + Author: Angelos Chalaris (chalarangelo@gmail.com) + Maintainers: Angelos Chalaris + mini.css version: v3.0.0-alpha.3 +*/ +/* + Browsers resets and base typography. +*/ +/* Core module CSS variable definitions */ +:root { + --fore-color: #111; + --secondary-fore-color: #444; + --back-color: #f8f8f8; + --secondary-back-color: #f0f0f0; + --blockquote-color: #f57c00; + --pre-color: #1565c0; + --border-color: #aaa; + --secondary-border-color: #ddd; + --heading-ratio: 1.19; + --universal-margin: 0.5rem; + --universal-padding: 0.125rem; + --universal-border-radius: 0.125rem; + --a-link-color: #0277bd; + --a-visited-color: #01579b; } + +html { + font-size: 14px; } + +a, b, del, em, i, ins, q, span, strong, u { + font-size: 1em; } + +html, * { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", Helvetica, sans-serif; + line-height: 1.4; + -webkit-text-size-adjust: 100%; } + +* { + font-size: 1rem; } + +body { + margin: 0; + color: var(--fore-color); + background: var(--back-color); } + +details { + display: block; } + +summary { + display: list-item; } + +abbr[title] { + border-bottom: none; + text-decoration: underline dotted; } + +input { + overflow: visible; } + +img { + max-width: 100%; + height: auto; } + +h1, h2, h3, h4, h5, h6 { + line-height: 1.2; + margin: calc(1.5 * var(--universal-margin)) var(--universal-margin); + font-weight: 500; } + h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { + color: var(--secondary-fore-color); + display: block; + margin-top: -0.25rem; } + +h1 { + font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio)); } + +h2 { + font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio); ); + background: var(--mark-back-color); + font-weight: 600; + padding: 0.1em 0.5em 0.2em 0.5em; + color: var(--mark-fore-color); } + +h3 { + font-size: calc(1rem * var(--heading-ratio)); + padding-left: calc(2 * var(--universal-margin)); + /* background: var(--border-color); */ + } + +h4 { + font-size: 1rem;); + padding-left: calc(4 * var(--universal-margin)); } + +h5 { + font-size: 1rem; } + +h6 { + font-size: calc(1rem / var(--heading-ratio)); } + +p { + margin: var(--universal-margin); } + +ol, ul { + margin: var(--universal-margin); + padding-left: calc(6 * var(--universal-margin)); } + +b, strong { + font-weight: 700; } + +hr { + box-sizing: content-box; + border: 0; + line-height: 1.25em; + margin: var(--universal-margin); + height: 0.0625rem; + background: linear-gradient(to right, transparent, var(--border-color) 20%, var(--border-color) 80%, transparent); } + +blockquote { + display: block; + position: relative; + font-style: italic; + color: var(--secondary-fore-color); + margin: var(--universal-margin); + padding: calc(3 * var(--universal-padding)); + border: 0.0625rem solid var(--secondary-border-color); + border-left: 0.375rem solid var(--blockquote-color); + border-radius: 0 var(--universal-border-radius) var(--universal-border-radius) 0; } + blockquote:before { + position: absolute; + top: calc(0rem - var(--universal-padding)); + left: 0; + font-family: sans-serif; + font-size: 3rem; + font-weight: 700; + content: "\201c"; + color: var(--blockquote-color); } + blockquote[cite]:after { + font-style: normal; + font-size: 0.75em; + font-weight: 700; + content: "\a— " attr(cite); + white-space: pre; } + +code, kbd, pre, samp { + font-family: Menlo, Consolas, monospace; + font-size: 0.85em; } + +code { + background: var(--secondary-back-color); + border-radius: var(--universal-border-radius); + padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); } + +kbd { + background: var(--fore-color); + color: var(--back-color); + border-radius: var(--universal-border-radius); + padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); } + +pre { + overflow: auto; + background: var(--secondary-back-color); + padding: calc(1.5 * var(--universal-padding)); + margin: var(--universal-margin); + border: 0.0625rem solid var(--secondary-border-color); + border-left: 0.25rem solid var(--pre-color); + border-radius: 0 var(--universal-border-radius) var(--universal-border-radius) 0; } + +sup, sub, code, kbd { + line-height: 0; + position: relative; + vertical-align: baseline; } + +small, sup, sub, figcaption { + font-size: 0.75em; } + +sup { + top: -0.5em; } + +sub { + bottom: -0.25em; } + +figure { + margin: var(--universal-margin); } + +figcaption { + color: var(--secondary-fore-color); } + +a { + text-decoration: none; } + a:link { + color: var(--a-link-color); } + a:visited { + color: var(--a-visited-color); } + a:hover, a:focus { + text-decoration: underline; } + +/* + Definitions for the grid system, cards and containers. +*/ +.container { + margin: 0 auto; + padding: 0 calc(1.5 * var(--universal-padding)); } + +.row { + box-sizing: border-box; + display: flex; + flex: 0 1 auto; + flex-flow: row wrap; } + +.col-sm, +[class^='col-sm-'], +[class^='col-sm-offset-'], +.row[class*='cols-sm-'] > * { + box-sizing: border-box; + flex: 0 0 auto; + padding: 0 calc(var(--universal-padding) / 2); } + +.col-sm, +.row.cols-sm > * { + max-width: 100%; + flex-grow: 1; + flex-basis: 0; } + +.col-sm-1, +.row.cols-sm-1 > * { + max-width: 8.3333333333%; + flex-basis: 8.3333333333%; } + +.col-sm-offset-0 { + margin-left: 0; } + +.col-sm-2, +.row.cols-sm-2 > * { + max-width: 16.6666666667%; + flex-basis: 16.6666666667%; } + +.col-sm-offset-1 { + margin-left: 8.3333333333%; } + +.col-sm-3, +.row.cols-sm-3 > * { + max-width: 25%; + flex-basis: 25%; } + +.col-sm-offset-2 { + margin-left: 16.6666666667%; } + +.col-sm-4, +.row.cols-sm-4 > * { + max-width: 33.3333333333%; + flex-basis: 33.3333333333%; } + +.col-sm-offset-3 { + margin-left: 25%; } + +.col-sm-5, +.row.cols-sm-5 > * { + max-width: 41.6666666667%; + flex-basis: 41.6666666667%; } + +.col-sm-offset-4 { + margin-left: 33.3333333333%; } + +.col-sm-6, +.row.cols-sm-6 > * { + max-width: 50%; + flex-basis: 50%; } + +.col-sm-offset-5 { + margin-left: 41.6666666667%; } + +.col-sm-7, +.row.cols-sm-7 > * { + max-width: 58.3333333333%; + flex-basis: 58.3333333333%; } + +.col-sm-offset-6 { + margin-left: 50%; } + +.col-sm-8, +.row.cols-sm-8 > * { + max-width: 66.6666666667%; + flex-basis: 66.6666666667%; } + +.col-sm-offset-7 { + margin-left: 58.3333333333%; } + +.col-sm-9, +.row.cols-sm-9 > * { + max-width: 75%; + flex-basis: 75%; } + +.col-sm-offset-8 { + margin-left: 66.6666666667%; } + +.col-sm-10, +.row.cols-sm-10 > * { + max-width: 83.3333333333%; + flex-basis: 83.3333333333%; } + +.col-sm-offset-9 { + margin-left: 75%; } + +.col-sm-11, +.row.cols-sm-11 > * { + max-width: 91.6666666667%; + flex-basis: 91.6666666667%; } + +.col-sm-offset-10 { + margin-left: 83.3333333333%; } + +.col-sm-12, +.row.cols-sm-12 > * { + max-width: 100%; + flex-basis: 100%; } + +.col-sm-offset-11 { + margin-left: 91.6666666667%; } + +.col-sm-normal { + order: initial; } + +.col-sm-first { + order: -999; } + +.col-sm-last { + order: 999; } + +@media screen and (min-width: 500px) { + .col-md, + [class^='col-md-'], + [class^='col-md-offset-'], + .row[class*='cols-md-'] > * { + box-sizing: border-box; + flex: 0 0 auto; + padding: 0 calc(var(--universal-padding) / 2); } + + .col-md, + .row.cols-md > * { + max-width: 100%; + flex-grow: 1; + flex-basis: 0; } + + .col-md-1, + .row.cols-md-1 > * { + max-width: 8.3333333333%; + flex-basis: 8.3333333333%; } + + .col-md-offset-0 { + margin-left: 0; } + + .col-md-2, + .row.cols-md-2 > * { + max-width: 16.6666666667%; + flex-basis: 16.6666666667%; } + + .col-md-offset-1 { + margin-left: 8.3333333333%; } + + .col-md-3, + .row.cols-md-3 > * { + max-width: 25%; + flex-basis: 25%; } + + .col-md-offset-2 { + margin-left: 16.6666666667%; } + + .col-md-4, + .row.cols-md-4 > * { + max-width: 33.3333333333%; + flex-basis: 33.3333333333%; } + + .col-md-offset-3 { + margin-left: 25%; } + + .col-md-5, + .row.cols-md-5 > * { + max-width: 41.6666666667%; + flex-basis: 41.6666666667%; } + + .col-md-offset-4 { + margin-left: 33.3333333333%; } + + .col-md-6, + .row.cols-md-6 > * { + max-width: 50%; + flex-basis: 50%; } + + .col-md-offset-5 { + margin-left: 41.6666666667%; } + + .col-md-7, + .row.cols-md-7 > * { + max-width: 58.3333333333%; + flex-basis: 58.3333333333%; } + + .col-md-offset-6 { + margin-left: 50%; } + + .col-md-8, + .row.cols-md-8 > * { + max-width: 66.6666666667%; + flex-basis: 66.6666666667%; } + + .col-md-offset-7 { + margin-left: 58.3333333333%; } + + .col-md-9, + .row.cols-md-9 > * { + max-width: 75%; + flex-basis: 75%; } + + .col-md-offset-8 { + margin-left: 66.6666666667%; } + + .col-md-10, + .row.cols-md-10 > * { + max-width: 83.3333333333%; + flex-basis: 83.3333333333%; } + + .col-md-offset-9 { + margin-left: 75%; } + + .col-md-11, + .row.cols-md-11 > * { + max-width: 91.6666666667%; + flex-basis: 91.6666666667%; } + + .col-md-offset-10 { + margin-left: 83.3333333333%; } + + .col-md-12, + .row.cols-md-12 > * { + max-width: 100%; + flex-basis: 100%; } + + .col-md-offset-11 { + margin-left: 91.6666666667%; } + + .col-md-normal { + order: initial; } + + .col-md-first { + order: -999; } + + .col-md-last { + order: 999; } } +@media screen and (min-width: 1280px) { + .col-lg, + [class^='col-lg-'], + [class^='col-lg-offset-'], + .row[class*='cols-lg-'] > * { + box-sizing: border-box; + flex: 0 0 auto; + padding: 0 calc(var(--universal-padding) / 2); } + + .col-lg, + .row.cols-lg > * { + max-width: 100%; + flex-grow: 1; + flex-basis: 0; } + + .col-lg-1, + .row.cols-lg-1 > * { + max-width: 8.3333333333%; + flex-basis: 8.3333333333%; } + + .col-lg-offset-0 { + margin-left: 0; } + + .col-lg-2, + .row.cols-lg-2 > * { + max-width: 16.6666666667%; + flex-basis: 16.6666666667%; } + + .col-lg-offset-1 { + margin-left: 8.3333333333%; } + + .col-lg-3, + .row.cols-lg-3 > * { + max-width: 25%; + flex-basis: 25%; } + + .col-lg-offset-2 { + margin-left: 16.6666666667%; } + + .col-lg-4, + .row.cols-lg-4 > * { + max-width: 33.3333333333%; + flex-basis: 33.3333333333%; } + + .col-lg-offset-3 { + margin-left: 25%; } + + .col-lg-5, + .row.cols-lg-5 > * { + max-width: 41.6666666667%; + flex-basis: 41.6666666667%; } + + .col-lg-offset-4 { + margin-left: 33.3333333333%; } + + .col-lg-6, + .row.cols-lg-6 > * { + max-width: 50%; + flex-basis: 50%; } + + .col-lg-offset-5 { + margin-left: 41.6666666667%; } + + .col-lg-7, + .row.cols-lg-7 > * { + max-width: 58.3333333333%; + flex-basis: 58.3333333333%; } + + .col-lg-offset-6 { + margin-left: 50%; } + + .col-lg-8, + .row.cols-lg-8 > * { + max-width: 66.6666666667%; + flex-basis: 66.6666666667%; } + + .col-lg-offset-7 { + margin-left: 58.3333333333%; } + + .col-lg-9, + .row.cols-lg-9 > * { + max-width: 75%; + flex-basis: 75%; } + + .col-lg-offset-8 { + margin-left: 66.6666666667%; } + + .col-lg-10, + .row.cols-lg-10 > * { + max-width: 83.3333333333%; + flex-basis: 83.3333333333%; } + + .col-lg-offset-9 { + margin-left: 75%; } + + .col-lg-11, + .row.cols-lg-11 > * { + max-width: 91.6666666667%; + flex-basis: 91.6666666667%; } + + .col-lg-offset-10 { + margin-left: 83.3333333333%; } + + .col-lg-12, + .row.cols-lg-12 > * { + max-width: 100%; + flex-basis: 100%; } + + .col-lg-offset-11 { + margin-left: 91.6666666667%; } + + .col-lg-normal { + order: initial; } + + .col-lg-first { + order: -999; } + + .col-lg-last { + order: 999; } } +/* Card component CSS variable definitions */ +:root { + --card-back-color: #f8f8f8; + --card-fore-color: #111; + --card-border-color: #ddd; } + +.card { + display: flex; + flex-direction: column; + justify-content: space-between; + align-self: center; + position: relative; + width: 100%; + background: var(--card-back-color); + color: var(--card-fore-color); + border: 0.0625rem solid var(--card-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); + overflow: hidden; } + @media screen and (min-width: 320px) { + .card { + max-width: 320px; } } + .card > .sectione { + background: var(--card-back-color); + color: var(--card-fore-color); + box-sizing: border-box; + margin: 0; + border: 0; + border-radius: 0; + border-bottom: 0.0625rem solid var(--card-border-color); + padding: var(--universal-padding); + width: 100%; } + .card > .sectione.media { + height: 200px; + padding: 0; + -o-object-fit: cover; + object-fit: cover; } + .card > .sectione:last-child { + border-bottom: 0; } + +/* + Custom elements for card elements. +*/ +@media screen and (min-width: 240px) { + .card.small { + max-width: 240px; } } +@media screen and (min-width: 480px) { + .card.large { + max-width: 480px; } } +.card.fluid { + max-width: 100%; + width: auto; } + +.card.warning { +/* --card-back-color: #ffca28; */ + --card-back-color: #e5b8b7; + --card-border-color: #e8b825; } + +.card.error { + --card-back-color: #b71c1c; + --card-fore-color: #f8f8f8; + --card-border-color: #a71a1a; } + +.card > .sectione.dark { + --card-back-color: #e0e0e0; } + +.card > .sectione.double-padded { + padding: calc(1.5 * var(--universal-padding)); } + +/* + Definitions for forms and input elements. +*/ +/* Input_control module CSS variable definitions */ +:root { + --form-back-color: #f0f0f0; + --form-fore-color: #111; + --form-border-color: #ddd; + --input-back-color: #f8f8f8; + --input-fore-color: #111; + --input-border-color: #ddd; + --input-focus-color: #0288d1; + --input-invalid-color: #d32f2f; + --button-back-color: #e2e2e2; + --button-hover-back-color: #dcdcdc; + --button-fore-color: #212121; + --button-border-color: transparent; + --button-hover-border-color: transparent; + --button-group-border-color: rgba(124, 124, 124, 0.54); } + +form { + background: var(--form-back-color); + color: var(--form-fore-color); + border: 0.0625rem solid var(--form-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); + padding: calc(2 * var(--universal-padding)) var(--universal-padding); } + +fieldset { + border: 0.0625rem solid var(--form-border-color); + border-radius: var(--universal-border-radius); + margin: calc(var(--universal-margin) / 4); + padding: var(--universal-padding); } + +legend { + box-sizing: border-box; + display: table; + max-width: 100%; + white-space: normal; + font-weight: 700; + padding: calc(var(--universal-padding) / 2); } + +label { + padding: calc(var(--universal-padding) / 2) var(--universal-padding); } + +.input-group { + display: inline-block; } + .input-group.fluid { + display: flex; + align-items: center; + justify-content: center; } + .input-group.fluid > input { + max-width: 100%; + flex-grow: 1; + flex-basis: 0px; } + @media screen and (max-width: 499px) { + .input-group.fluid { + align-items: stretch; + flex-direction: column; } } + .input-group.vertical { + display: flex; + align-items: stretch; + flex-direction: column; } + .input-group.vertical > input { + max-width: 100%; + flex-grow: 1; + flex-basis: 0px; } + +[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { + height: auto; } + +[type="search"] { + -webkit-appearance: textfield; + outline-offset: -2px; } + +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; } + +input:not([type]), [type="text"], [type="email"], [type="number"], [type="search"], +[type="password"], [type="url"], [type="tel"], [type="checkbox"], [type="radio"], textarea, select { + box-sizing: border-box; + background: var(--input-back-color); + color: var(--input-fore-color); + border: 0.0625rem solid var(--input-border-color); + border-radius: var(--universal-border-radius); + margin: calc(var(--universal-margin) / 2); + padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); } + +input:not([type="button"]):not([type="submit"]):not([type="reset"]):hover, input:not([type="button"]):not([type="submit"]):not([type="reset"]):focus, textarea:hover, textarea:focus, select:hover, select:focus { + border-color: var(--input-focus-color); + box-shadow: none; } +input:not([type="button"]):not([type="submit"]):not([type="reset"]):invalid, input:not([type="button"]):not([type="submit"]):not([type="reset"]):focus:invalid, textarea:invalid, textarea:focus:invalid, select:invalid, select:focus:invalid { + border-color: var(--input-invalid-color); + box-shadow: none; } +input:not([type="button"]):not([type="submit"]):not([type="reset"])[readonly], textarea[readonly], select[readonly] { + background: var(--secondary-back-color); } + +select { + max-width: 100%; } + +option { + overflow: hidden; + text-overflow: ellipsis; } + +[type="checkbox"], [type="radio"] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + position: relative; + height: calc(1rem + var(--universal-padding) / 2); + width: calc(1rem + var(--universal-padding) / 2); + vertical-align: text-bottom; + padding: 0; + flex-basis: calc(1rem + var(--universal-padding) / 2) !important; + flex-grow: 0 !important; } + [type="checkbox"]:checked:before, [type="radio"]:checked:before { + position: absolute; } + +[type="checkbox"]:checked:before { + content: '\2713'; + font-family: sans-serif; + font-size: calc(1rem + var(--universal-padding) / 2); + top: calc(0rem - var(--universal-padding)); + left: calc(var(--universal-padding) / 4); } + +[type="radio"] { + border-radius: 100%; } + [type="radio"]:checked:before { + border-radius: 100%; + content: ''; + top: calc(0.0625rem + var(--universal-padding) / 2); + left: calc(0.0625rem + var(--universal-padding) / 2); + background: var(--input-fore-color); + width: 0.5rem; + height: 0.5rem; } + +:placeholder-shown { + color: var(--input-fore-color); } + +::-ms-placeholder { + color: var(--input-fore-color); + opacity: 0.54; } + +button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; } + +button, html [type="button"], [type="reset"], [type="submit"] { + -webkit-appearance: button; } + +button { + overflow: visible; + text-transform: none; } + +button, [type="button"], [type="submit"], [type="reset"], +a.button, label.button, .button, +a[role="button"], label[role="button"], [role="button"] { + display: inline-block; + background: var(--button-back-color); + color: var(--button-fore-color); + border: 0.0625rem solid var(--button-border-color); + border-radius: var(--universal-border-radius); + padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); + margin: var(--universal-margin); + text-decoration: none; + cursor: pointer; + transition: background 0.3s; } + button:hover, button:focus, [type="button"]:hover, [type="button"]:focus, [type="submit"]:hover, [type="submit"]:focus, [type="reset"]:hover, [type="reset"]:focus, + a.button:hover, + a.button:focus, label.button:hover, label.button:focus, .button:hover, .button:focus, + a[role="button"]:hover, + a[role="button"]:focus, label[role="button"]:hover, label[role="button"]:focus, [role="button"]:hover, [role="button"]:focus { + background: var(--button-hover-back-color); + border-color: var(--button-hover-border-color); } + +input:disabled, input[disabled], textarea:disabled, textarea[disabled], select:disabled, select[disabled], button:disabled, button[disabled], .button:disabled, .button[disabled], [role="button"]:disabled, [role="button"][disabled] { + cursor: not-allowed; + opacity: 0.75; } + +.button-group { + display: flex; + border: 0.0625rem solid var(--button-group-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); } + .button-group > button, .button-group [type="button"], .button-group > [type="submit"], .button-group > [type="reset"], .button-group > .button, .button-group > [role="button"] { + margin: 0; + max-width: 100%; + flex: 1 1 auto; + text-align: center; + border: 0; + border-radius: 0; + box-shadow: none; } + .button-group > :not(:first-child) { + border-left: 0.0625rem solid var(--button-group-border-color); } + @media screen and (max-width: 499px) { + .button-group { + flex-direction: column; } + .button-group > :not(:first-child) { + border: 0; + border-top: 0.0625rem solid var(--button-group-border-color); } } + +/* + Custom elements for forms and input elements. +*/ +button.primary, [type="button"].primary, [type="submit"].primary, [type="reset"].primary, .button.primary, [role="button"].primary { + --button-back-color: #1976d2; + --button-fore-color: #f8f8f8; } + button.primary:hover, button.primary:focus, [type="button"].primary:hover, [type="button"].primary:focus, [type="submit"].primary:hover, [type="submit"].primary:focus, [type="reset"].primary:hover, [type="reset"].primary:focus, .button.primary:hover, .button.primary:focus, [role="button"].primary:hover, [role="button"].primary:focus { + --button-hover-back-color: #1565c0; } + +button.secondary, [type="button"].secondary, [type="submit"].secondary, [type="reset"].secondary, .button.secondary, [role="button"].secondary { + --button-back-color: #d32f2f; + --button-fore-color: #f8f8f8; } + button.secondary:hover, button.secondary:focus, [type="button"].secondary:hover, [type="button"].secondary:focus, [type="submit"].secondary:hover, [type="submit"].secondary:focus, [type="reset"].secondary:hover, [type="reset"].secondary:focus, .button.secondary:hover, .button.secondary:focus, [role="button"].secondary:hover, [role="button"].secondary:focus { + --button-hover-back-color: #c62828; } + +button.tertiary, [type="button"].tertiary, [type="submit"].tertiary, [type="reset"].tertiary, .button.tertiary, [role="button"].tertiary { + --button-back-color: #308732; + --button-fore-color: #f8f8f8; } + button.tertiary:hover, button.tertiary:focus, [type="button"].tertiary:hover, [type="button"].tertiary:focus, [type="submit"].tertiary:hover, [type="submit"].tertiary:focus, [type="reset"].tertiary:hover, [type="reset"].tertiary:focus, .button.tertiary:hover, .button.tertiary:focus, [role="button"].tertiary:hover, [role="button"].tertiary:focus { + --button-hover-back-color: #277529; } + +button.inverse, [type="button"].inverse, [type="submit"].inverse, [type="reset"].inverse, .button.inverse, [role="button"].inverse { + --button-back-color: #212121; + --button-fore-color: #f8f8f8; } + button.inverse:hover, button.inverse:focus, [type="button"].inverse:hover, [type="button"].inverse:focus, [type="submit"].inverse:hover, [type="submit"].inverse:focus, [type="reset"].inverse:hover, [type="reset"].inverse:focus, .button.inverse:hover, .button.inverse:focus, [role="button"].inverse:hover, [role="button"].inverse:focus { + --button-hover-back-color: #111; } + +button.small, [type="button"].small, [type="submit"].small, [type="reset"].small, .button.small, [role="button"].small { + padding: calc(0.5 * var(--universal-padding)) calc(0.75 * var(--universal-padding)); + margin: var(--universal-margin); } + +button.large, [type="button"].large, [type="submit"].large, [type="reset"].large, .button.large, [role="button"].large { + padding: calc(1.5 * var(--universal-padding)) calc(2 * var(--universal-padding)); + margin: var(--universal-margin); } + +/* + Definitions for navigation elements. +*/ +/* Navigation module CSS variable definitions */ +:root { + --header-back-color: #f8f8f8; + --header-hover-back-color: #f0f0f0; + --header-fore-color: #444; + --header-border-color: #ddd; + --nav-back-color: #f8f8f8; + --nav-hover-back-color: #f0f0f0; + --nav-fore-color: #444; + --nav-border-color: #ddd; + --nav-link-color: #0277bd; + --footer-fore-color: #444; + --footer-back-color: #f8f8f8; + --footer-border-color: #ddd; + --footer-link-color: #0277bd; + --drawer-back-color: #f8f8f8; + --drawer-hover-back-color: #f0f0f0; + --drawer-border-color: #ddd; + --drawer-close-color: #444; } + +header { + height: 3.1875rem; + background: var(--header-back-color); + color: var(--header-fore-color); + border-bottom: 0.0625rem solid var(--header-border-color); + padding: calc(var(--universal-padding) / 4) 0; + white-space: nowrap; + overflow-x: auto; + overflow-y: hidden; } + header.row { + box-sizing: content-box; } + header .logo { + color: var(--header-fore-color); + font-size: 1.75rem; + padding: var(--universal-padding) calc(2 * var(--universal-padding)); + text-decoration: none; } + header button, header [type="button"], header .button, header [role="button"] { + box-sizing: border-box; + position: relative; + top: calc(0rem - var(--universal-padding) / 4); + height: calc(3.1875rem + var(--universal-padding) / 2); + background: var(--header-back-color); + line-height: calc(3.1875rem - var(--universal-padding) * 1.5); + text-align: center; + color: var(--header-fore-color); + border: 0; + border-radius: 0; + margin: 0; + text-transform: uppercase; } + header button:hover, header button:focus, header [type="button"]:hover, header [type="button"]:focus, header .button:hover, header .button:focus, header [role="button"]:hover, header [role="button"]:focus { + background: var(--header-hover-back-color); } + +nav { + background: var(--nav-back-color); + color: var(--nav-fore-color); + border: 0.0625rem solid var(--nav-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); } + nav * { + padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); } + nav a, nav a:visited { + display: block; + color: var(--nav-link-color); + border-radius: var(--universal-border-radius); + transition: background 0.3s; } + nav a:hover, nav a:focus, nav a:visited:hover, nav a:visited:focus { + text-decoration: none; + background: var(--nav-hover-back-color); } + nav .sublink-1 { + position: relative; + margin-left: calc(2 * var(--universal-padding)); } + nav .sublink-1:before { + position: absolute; + left: calc(var(--universal-padding) - 1 * var(--universal-padding)); + top: -0.0625rem; + content: ''; + height: 100%; + border: 0.0625rem solid var(--nav-border-color); + border-left: 0; } + nav .sublink-2 { + position: relative; + margin-left: calc(4 * var(--universal-padding)); } + nav .sublink-2:before { + position: absolute; + left: calc(var(--universal-padding) - 3 * var(--universal-padding)); + top: -0.0625rem; + content: ''; + height: 100%; + border: 0.0625rem solid var(--nav-border-color); + border-left: 0; } + +footer { + background: var(--footer-back-color); + color: var(--footer-fore-color); + border-top: 0.0625rem solid var(--footer-border-color); + padding: calc(2 * var(--universal-padding)) var(--universal-padding); + font-size: 0.875rem; } + footer a, footer a:visited { + color: var(--footer-link-color); } + +header.sticky { + position: -webkit-sticky; + position: sticky; + z-index: 1101; + top: 0; } + +footer.sticky { + position: -webkit-sticky; + position: sticky; + z-index: 1101; + bottom: 0; } + +.drawer-toggle:before { + display: inline-block; + position: relative; + vertical-align: bottom; + content: '\00a0\2261\00a0'; + font-family: sans-serif; + font-size: 1.5em; } +@media screen and (min-width: 500px) { + .drawer-toggle:not(.persistent) { + display: none; } } + +[type="checkbox"].drawer { + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); } + [type="checkbox"].drawer + * { + display: block; + box-sizing: border-box; + position: fixed; + top: 0; + width: 320px; + height: 100vh; + overflow-y: auto; + background: var(--drawer-back-color); + border: 0.0625rem solid var(--drawer-border-color); + border-radius: 0; + margin: 0; + z-index: 1110; + right: -320px; + transition: right 0.3s; } + [type="checkbox"].drawer + * .drawer-close { + position: absolute; + top: var(--universal-margin); + right: var(--universal-margin); + z-index: 1111; + width: 2rem; + height: 2rem; + border-radius: var(--universal-border-radius); + padding: var(--universal-padding); + margin: 0; + cursor: pointer; + transition: background 0.3s; } + [type="checkbox"].drawer + * .drawer-close:before { + display: block; + content: '\00D7'; + color: var(--drawer-close-color); + position: relative; + font-family: sans-serif; + font-size: 2rem; + line-height: 1; + text-align: center; } + [type="checkbox"].drawer + * .drawer-close:hover, [type="checkbox"].drawer + * .drawer-close:focus { + background: var(--drawer-hover-back-color); } + @media screen and (max-width: 320px) { + [type="checkbox"].drawer + * { + width: 100%; } } + [type="checkbox"].drawer:checked + * { + right: 0; } + @media screen and (min-width: 500px) { + [type="checkbox"].drawer:not(.persistent) + * { + position: static; + height: 100%; + z-index: 1100; } + [type="checkbox"].drawer:not(.persistent) + * .drawer-close { + display: none; } } + +/* + Definitions for the responsive table component. +*/ +/* Table module CSS variable definitions. */ +:root { + --table-border-color: #aaa; + --table-border-separator-color: #666; + --table-head-back-color: #e6e6e6; + --table-head-fore-color: #111; + --table-body-back-color: #f8f8f8; + --table-body-fore-color: #111; + --table-body-alt-back-color: #eee; } + +table { + border-collapse: separate; + border-spacing: 0; + : margin: calc(1.5 * var(--universal-margin)) var(--universal-margin); + display: flex; + flex: 0 1 auto; + flex-flow: row wrap; + padding: var(--universal-padding); + padding-top: 0; + margin: calc(1.5 * var(--universal-margin)) var(--universal-margin); } + table caption { + font-size: 1.25 * rem; + margin: calc(2 * var(--universal-margin)) 0; + max-width: 100%; + flex: 0 0 100%; + text-align: left;} + table thead, table tbody { + display: flex; + flex-flow: row wrap; + border: 0.0625rem solid var(--table-border-color); } + table thead { + z-index: 999; + border-radius: var(--universal-border-radius) var(--universal-border-radius) 0 0; + border-bottom: 0.0625rem solid var(--table-border-separator-color); } + table tbody { + border-top: 0; + margin-top: calc(0 - var(--universal-margin)); + border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); } + table tr { + display: flex; + padding: 0; } + table th, table td { + padding: calc(0.5 * var(--universal-padding)); + font-size: 0.9rem; } + table th { + text-align: left; + background: var(--table-head-back-color); + color: var(--table-head-fore-color); } + table td { + background: var(--table-body-back-color); + color: var(--table-body-fore-color); + border-top: 0.0625rem solid var(--table-border-color); } + +table:not(.horizontal) { + overflow: auto; + max-height: 850px; } + table:not(.horizontal) thead, table:not(.horizontal) tbody { + max-width: 100%; + flex: 0 0 100%; } + table:not(.horizontal) tr { + flex-flow: row wrap; + flex: 0 0 100%; } + table:not(.horizontal) th, table:not(.horizontal) td { + flex: 1 0 0%; + overflow: hidden; + text-overflow: ellipsis; } + table:not(.horizontal) thead { + position: sticky; + top: 0; } + table:not(.horizontal) tbody tr:first-child td { + border-top: 0; } + +table.horizontal { + border: 0; } + table.horizontal thead, table.horizontal tbody { + border: 0; + flex-flow: row nowrap; } + table.horizontal tbody { + overflow: auto; + justify-content: space-between; + flex: 1 0 0; + margin-left: calc( 4 * var(--universal-margin)); + padding-bottom: calc(var(--universal-padding) / 4); } + table.horizontal tr { + flex-direction: column; + flex: 1 0 auto; } + table.horizontal th, table.horizontal td { + width: 100%; + border: 0; + border-bottom: 0.0625rem solid var(--table-border-color); } + table.horizontal th:not(:first-child), table.horizontal td:not(:first-child) { + border-top: 0; } + table.horizontal th { + text-align: right; + border-left: 0.0625rem solid var(--table-border-color); + border-right: 0.0625rem solid var(--table-border-separator-color); } + table.horizontal thead tr:first-child { + padding-left: 0; } + table.horizontal th:first-child, table.horizontal td:first-child { + border-top: 0.0625rem solid var(--table-border-color); } + table.horizontal tbody tr:last-child td { + border-right: 0.0625rem solid var(--table-border-color); } + table.horizontal tbody tr:last-child td:first-child { + border-top-right-radius: 0.25rem; } + table.horizontal tbody tr:last-child td:last-child { + border-bottom-right-radius: 0.25rem; } + table.horizontal thead tr:first-child th:first-child { + border-top-left-radius: 0.25rem; } + table.horizontal thead tr:first-child th:last-child { + border-bottom-left-radius: 0.25rem; } + +@media screen and (max-width: 499px) { + table, table.horizontal { + border-collapse: collapse; + border: 0; + width: 100%; + display: table; } + table thead, table th, table.horizontal thead, table.horizontal th { + border: 0; + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); } + table tbody, table.horizontal tbody { + border: 0; + display: table-row-group; } + table tr, table.horizontal tr { + display: block; + border: 0.0625rem solid var(--table-border-color); + border-radius: var(--universal-border-radius); + background: #fafafa; + padding: var(--universal-padding); + margin: var(--universal-margin); + margin-bottom: calc(2 * var(--universal-margin)); } + table th, table td, table.horizontal th, table.horizontal td { + width: auto; } + table td, table.horizontal td { + display: block; + border: 0; + text-align: right; } + table td:before, table.horizontal td:before { + content: attr(data-label); + float: left; + font-weight: 600; } + table th:first-child, table td:first-child, table.horizontal th:first-child, table.horizontal td:first-child { + border-top: 0; } + table tbody tr:last-child td, table.horizontal tbody tr:last-child td { + border-right: 0; } } +:root { + --table-body-alt-back-color: #eee; } + +table tr:nth-of-type(2n) > td { + background: var(--table-body-alt-back-color); } + +@media screen and (max-width: 500px) { + table tr:nth-of-type(2n) { + background: var(--table-body-alt-back-color); } } +:root { + --table-body-hover-back-color: #90caf9; } + +table.hoverable tr:hover, table.hoverable tr:hover > td, table.hoverable tr:focus, table.hoverable tr:focus > td { + background: var(--table-body-hover-back-color); } + +@media screen and (max-width: 500px) { + table.hoverable tr:hover, table.hoverable tr:hover > td, table.hoverable tr:focus, table.hoverable tr:focus > td { + background: var(--table-body-hover-back-color); } } +/* + Definitions for contextual background elements, toasts and tooltips. +*/ +/* Contextual module CSS variable definitions */ +:root { + --mark-back-color: #0277bd; + --mark-fore-color: #fafafa; } + +mark { + background: var(--mark-back-color); + color: var(--mark-fore-color); + font-size: 0.95em; + line-height: 1em; + border-radius: var(--universal-border-radius); + padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); } + mark.inline-block { + display: inline-block; + font-size: 1em; + line-height: 1.5; + padding: calc(var(--universal-padding) / 2) var(--universal-padding); } + +:root { + --toast-back-color: #424242; + --toast-fore-color: #fafafa; } + +.toast { + position: fixed; + bottom: calc(var(--universal-margin) * 3); + left: 50%; + transform: translate(-50%, -50%); + z-index: 1111; + color: var(--toast-fore-color); + background: var(--toast-back-color); + border-radius: calc(var(--universal-border-radius) * 16); + padding: var(--universal-padding) calc(var(--universal-padding) * 3); } + +:root { + --tooltip-back-color: #212121; + --tooltip-fore-color: #fafafa; } + +.tooltip { + position: relative; + display: inline-block; } + .tooltip:before, .tooltip:after { + position: absolute; + opacity: 0; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + transition: all 0.3s; + z-index: 1010; + left: 50%; } + .tooltip:not(.bottom):before, .tooltip:not(.bottom):after { + bottom: 75%; } + .tooltip.bottom:before, .tooltip.bottom:after { + top: 75%; } + .tooltip:hover:before, .tooltip:hover:after, .tooltip:focus:before, .tooltip:focus:after { + opacity: 1; + clip: auto; + -webkit-clip-path: inset(0%); + clip-path: inset(0%); } + .tooltip:before { + content: ''; + background: transparent; + border: var(--universal-margin) solid transparent; + left: calc(50% - var(--universal-margin)); } + .tooltip:not(.bottom):before { + border-top-color: #212121; } + .tooltip.bottom:before { + border-bottom-color: #212121; } + .tooltip:after { + content: attr(aria-label); + color: var(--tooltip-fore-color); + background: var(--tooltip-back-color); + border-radius: var(--universal-border-radius); + padding: var(--universal-padding); + white-space: nowrap; + transform: translateX(-50%); } + .tooltip:not(.bottom):after { + margin-bottom: calc(2 * var(--universal-margin)); } + .tooltip.bottom:after { + margin-top: calc(2 * var(--universal-margin)); } + +:root { + --modal-overlay-color: rgba(0, 0, 0, 0.45); + --modal-close-color: #444; + --modal-close-hover-color: #f0f0f0; } + +[type="checkbox"].modal { + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); } + [type="checkbox"].modal + div { + position: fixed; + top: 0; + left: 0; + display: none; + width: 100vw; + height: 100vh; + background: var(--modal-overlay-color); } + [type="checkbox"].modal + div .card { + margin: 0 auto; + max-height: 50vh; + overflow: auto; } + [type="checkbox"].modal + div .card .modal-close { + position: absolute; + top: 0; + right: 0; + width: 1.75rem; + height: 1.75rem; + border-radius: var(--universal-border-radius); + padding: var(--universal-padding); + margin: 0; + cursor: pointer; + transition: background 0.3s; } + [type="checkbox"].modal + div .card .modal-close:before { + display: block; + content: '\00D7'; + color: var(--modal-close-color); + position: relative; + font-family: sans-serif; + font-size: 1.75rem; + line-height: 1; + text-align: center; } + [type="checkbox"].modal + div .card .modal-close:hover, [type="checkbox"].modal + div .card .modal-close:focus { + background: var(--modal-close-hover-color); } + [type="checkbox"].modal:checked + div { + display: flex; + flex: 0 1 auto; + z-index: 1200; } + [type="checkbox"].modal:checked + div .card .modal-close { + z-index: 1211; } + +:root { + --collapse-label-back-color: #e8e8e8; + --collapse-label-fore-color: #212121; + --collapse-label-hover-back-color: #f0f0f0; + --collapse-selected-label-back-color: #ececec; + --collapse-border-color: #ddd; + --collapse-content-back-color: #fafafa; + --collapse-selected-label-border-color: #0277bd; } + +.collapse { + width: calc(100% - 2 * var(--universal-margin)); + opacity: 1; + display: flex; + flex-direction: column; + margin: var(--universal-margin); + border-radius: var(--universal-border-radius); } + .collapse > [type="radio"], .collapse > [type="checkbox"] { + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); } + .collapse > label { + flex-grow: 1; + display: inline-block; + height: 1.5rem; + cursor: pointer; + transition: background 0.3s; + color: var(--collapse-label-fore-color); + background: var(--collapse-label-back-color); + border: 0.0625rem solid var(--collapse-border-color); + padding: calc(1.5 * var(--universal-padding)); } + .collapse > label:hover, .collapse > label:focus { + background: var(--collapse-label-hover-back-color); } + .collapse > label + div { + flex-basis: auto; + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + transition: max-height 0.3s; + max-height: 1px; } + .collapse > :checked + label { + background: var(--collapse-selected-label-back-color); + border-bottom-color: var(--collapse-selected-label-border-color); } + .collapse > :checked + label + div { + box-sizing: border-box; + position: relative; + width: 100%; + height: auto; + overflow: auto; + margin: 0; + background: var(--collapse-content-back-color); + border: 0.0625rem solid var(--collapse-border-color); + border-top: 0; + padding: var(--universal-padding); + clip: auto; + -webkit-clip-path: inset(0%); + clip-path: inset(0%); + max-height: 850px; } + .collapse > label:not(:first-of-type) { + border-top: 0; } + .collapse > label:first-of-type { + border-radius: var(--universal-border-radius) var(--universal-border-radius) 0 0; } + .collapse > label:last-of-type:not(:first-of-type) { + border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); } + .collapse > label:last-of-type:first-of-type { + border-radius: var(--universal-border-radius); } + .collapse > :checked:last-of-type:not(:first-of-type) + label { + border-radius: 0; } + .collapse > :checked:last-of-type + label + div { + border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); } + +/* + Custom elements for contextual background elements, toasts and tooltips. +*/ +mark.secondary { + --mark-back-color: #d32f2f; } + +mark.tertiary { + --mark-back-color: #308732; } + +mark.tag { + padding: calc(var(--universal-padding)/2) var(--universal-padding); + border-radius: 1em; } + +/* + Definitions for progress elements and spinners. +*/ +/* Progess module CSS variable definitions */ +:root { + --progress-back-color: #ddd; + --progress-fore-color: #555; } + +progress { + display: block; + vertical-align: baseline; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + height: 0.75rem; + width: calc(100% - 2 * var(--universal-margin)); + margin: var(--universal-margin); + border: 0; + border-radius: calc(2 * var(--universal-border-radius)); + background: var(--progress-back-color); + color: var(--progress-fore-color); } + progress::-webkit-progress-value { + background: var(--progress-fore-color); + border-top-left-radius: calc(2 * var(--universal-border-radius)); + border-bottom-left-radius: calc(2 * var(--universal-border-radius)); } + progress::-webkit-progress-bar { + background: var(--progress-back-color); } + progress::-moz-progress-bar { + background: var(--progress-fore-color); + border-top-left-radius: calc(2 * var(--universal-border-radius)); + border-bottom-left-radius: calc(2 * var(--universal-border-radius)); } + progress[value="1000"]::-webkit-progress-value { + border-radius: calc(2 * var(--universal-border-radius)); } + progress[value="1000"]::-moz-progress-bar { + border-radius: calc(2 * var(--universal-border-radius)); } + progress.inline { + display: inline-block; + vertical-align: middle; + width: 60%; } + +:root { + --spinner-back-color: #ddd; + --spinner-fore-color: #555; } + +@keyframes spinner-donut-anim { + 0% { + transform: rotate(0deg); } + 100% { + transform: rotate(360deg); } } +.spinner { + display: inline-block; + margin: var(--universal-margin); + border: 0.25rem solid var(--spinner-back-color); + border-left: 0.25rem solid var(--spinner-fore-color); + border-radius: 50%; + width: 1.25rem; + height: 1.25rem; + animation: spinner-donut-anim 1.2s linear infinite; } + +/* + Custom elements for progress bars and spinners. +*/ +progress.primary { + --progress-fore-color: #1976d2; } + +progress.secondary { + --progress-fore-color: #d32f2f; } + +progress.tertiary { + --progress-fore-color: #308732; } + +.spinner.primary { + --spinner-fore-color: #1976d2; } + +.spinner.secondary { + --spinner-fore-color: #d32f2f; } + +.spinner.tertiary { + --spinner-fore-color: #308732; } + +/* + Definitions for icons - powered by Feather (https://feathericons.com/). +*/ +span[class^='icon-'] { + display: inline-block; + height: 1em; + width: 1em; + vertical-align: -0.125em; + background-size: contain; + margin: 0 calc(var(--universal-margin) / 4); } + span[class^='icon-'].secondary { + -webkit-filter: invert(25%); + filter: invert(25%); } + span[class^='icon-'].inverse { + -webkit-filter: invert(100%); + filter: invert(100%); } + +span.icon-alert { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12' y2='16'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-bookmark { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-calendar { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-credit { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='1' y='4' width='22' height='16' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='1' y1='10' x2='23' y2='10'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-edit { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 14.66V20a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5.34'%3E%3C/path%3E%3Cpolygon points='18 2 22 6 12 16 8 16 8 12 18 2'%3E%3C/polygon%3E%3C/svg%3E"); } +span.icon-link { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'%3E%3C/path%3E%3Cpolyline points='15 3 21 3 21 9'%3E%3C/polyline%3E%3Cline x1='10' y1='14' x2='21' y2='3'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-help { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3'%3E%3C/path%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='17' x2='12' y2='17'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-home { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z'%3E%3C/path%3E%3Cpolyline points='9 22 9 12 15 12 15 22'%3E%3C/polyline%3E%3C/svg%3E"); } +span.icon-info { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='16' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='8' x2='12' y2='8'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-lock { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='11' width='18' height='11' rx='2' ry='2'%3E%3C/rect%3E%3Cpath d='M7 11V7a5 5 0 0 1 10 0v4'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-mail { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z'%3E%3C/path%3E%3Cpolyline points='22,6 12,13 2,6'%3E%3C/polyline%3E%3C/svg%3E"); } +span.icon-location { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z'%3E%3C/path%3E%3Ccircle cx='12' cy='10' r='3'%3E%3C/circle%3E%3C/svg%3E"); } +span.icon-phone { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-rss { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 11a9 9 0 0 1 9 9'%3E%3C/path%3E%3Cpath d='M4 4a16 16 0 0 1 16 16'%3E%3C/path%3E%3Ccircle cx='5' cy='19' r='1'%3E%3C/circle%3E%3C/svg%3E"); } +span.icon-search { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-settings { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='3'%3E%3C/circle%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-share { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='18' cy='5' r='3'%3E%3C/circle%3E%3Ccircle cx='6' cy='12' r='3'%3E%3C/circle%3E%3Ccircle cx='18' cy='19' r='3'%3E%3C/circle%3E%3Cline x1='8.59' y1='13.51' x2='15.42' y2='17.49'%3E%3C/line%3E%3Cline x1='15.41' y1='6.51' x2='8.59' y2='10.49'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-cart { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='21' r='1'%3E%3C/circle%3E%3Ccircle cx='20' cy='21' r='1'%3E%3C/circle%3E%3Cpath d='M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-upload { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'%3E%3C/path%3E%3Cpolyline points='17 8 12 3 7 8'%3E%3C/polyline%3E%3Cline x1='12' y1='3' x2='12' y2='15'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-user { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='12' cy='7' r='4'%3E%3C/circle%3E%3C/svg%3E"); } + +/* + Definitions for utilities and helper classes. +*/ +/* Utility module CSS variable definitions */ +:root { + --generic-border-color: rgba(0, 0, 0, 0.3); + --generic-box-shadow: 0 0.25rem 0.25rem 0 rgba(0, 0, 0, 0.125), 0 0.125rem 0.125rem -0.125rem rgba(0, 0, 0, 0.25); } + +.hidden { + display: none !important; } + +.visually-hidden { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; } + +.bordered { + border: 0.0625rem solid var(--generic-border-color) !important; } + +.rounded { + border-radius: var(--universal-border-radius) !important; } + +.circular { + border-radius: 50% !important; } + +.shadowed { + box-shadow: var(--generic-box-shadow) !important; } + +.responsive-margin { + margin: calc(var(--universal-margin) / 4) !important; } + @media screen and (min-width: 500px) { + .responsive-margin { + margin: calc(var(--universal-margin) / 2) !important; } } + @media screen and (min-width: 1280px) { + .responsive-margin { + margin: var(--universal-margin) !important; } } + +.responsive-padding { + padding: calc(var(--universal-padding) / 4) !important; } + @media screen and (min-width: 500px) { + .responsive-padding { + padding: calc(var(--universal-padding) / 2) !important; } } + @media screen and (min-width: 1280px) { + .responsive-padding { + padding: var(--universal-padding) !important; } } + +@media screen and (max-width: 499px) { + .hidden-sm { + display: none !important; } } +@media screen and (min-width: 500px) and (max-width: 1279px) { + .hidden-md { + display: none !important; } } +@media screen and (min-width: 1280px) { + .hidden-lg { + display: none !important; } } +@media screen and (max-width: 499px) { + .visually-hidden-sm { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; } } +@media screen and (min-width: 500px) and (max-width: 1279px) { + .visually-hidden-md { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; } } +@media screen and (min-width: 1280px) { + .visually-hidden-lg { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; } } + +/*# sourceMappingURL=mini-default.css.map */ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ov5640/_htmresc/st_logo.png b/src/port_stm32f7/common/bsp_drivers/Components/ov5640/_htmresc/st_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8b80057fd3a454a97de1c9d732b7fede82c83227 GIT binary patch literal 18616 zcmbTd^-~<*6D~X~?jgaQV8LAj0X_tm1Ydk1xVy{Z3GPmS;IP2r4oh%%cMl#Qcz~Pl zz5l>lZ`GVRHB&V|boY7A^z(F|Z=Y4=aIwg-006*MkpHOuZ?5<^0x;12-SsK9!v0Mt zmQpHG08kT${nrHb-!rC@ysj$%ki7ceKq56ESOEZeJ%x`_nqEey{^(v>eK${gL>pJ% zX8+KBAR_W-jhDrs{egi|sP<73DP`UFoa(>xj;8qknEx2bL~2@t%3k>}hnl@CWQrW@ zqfK>@e3$sL-m%ftg0YAkk!@=P!Ognuz(zhb|Tux{FeX<<7(5oLVU8=W*sUZ*$TqlSb6o1O0a zzeP#ZW!;?#>0N5v?0D|q?mzD8-<^@1V0FH{fY}2A9ooXbylcB6Y>PVo4nMxLi|AWA z8M(b#9`j|%0v7ktATOSzsh-T7%Wqa>t*x!29M*iDetE6#^`?iEoQW5F*w7rjcWYw>-UyKyDHetK@Im)qdu0o-zudq@gQN3)r z=(%XIh|%7(Y}2mODA6--)=u;7mi|lUCki50L@QOyZN@2N`Bwwn9et)BF?yQr9`Sn# ze!a;09%cuNiCJ+Hwx|5Sw&L`0rJvq<$7D5j#Y=O^YcW)1x!+MVRWRVHrXDj~g@40Q zBvp_niE6-dasJKX&t@%;X`7_R9QhT$w_Dv~zW73kCM;9WC z#^@^R#^^HZ#`rQ5ZjC*^uYUMgw=ae5*IV2JyEL@LlJ1k!yA8p=fmyQ={`Pjq&sK}Y>k9r>*Y-3njDRLc8z*D?su--n+y(fpV8FB zwS%vLw=L>F9>rMJzXaXgg5NRvaHPKO=qdV`%ecKE^q=CNs6^=Vl)5QG9h0>AKM-1F zvU-S)!Vnz~yg}XNmnaKSqm&}<1}#nOBCWZsLvn3_pkm8Z)~*KF8yv=yRk*!4rf$7T zT*ey^g`%>`O82HoVNPMCaM^5e_Eeop`^`Wsro=Q9SzJ-{LW5j1QdRH>Oq5bEX({TJ-TNGPvNBrk5{my=8FEQ%0fftv4 z)$FK)-usf%cyd|Y@=r@u!~HI3-5_Q=E%R!AkEqtv$Yv%Zit4K`i*n5tM!wdwLFM?% z@N0D&tLS9%TD>`41R~`%HzXtZS6pjo$}fsAA6cq`&Llq^TE@#ID4eU}(xZH$-0oa>g$RMe)N_S(=w@nXEL&?{|e zd%-=H@Ei^9kz3up?3!?QYr2O7^M9)q_E2E@^vESGQ&5WzDh<(QgQEd3BICrRm8O)S!fPO#z(h0}Vk) zolMw(Ecl!UD7xMUH0>?+9qzTMCMQxcM+Od*!L7F!tiwSSG>D@|J~*c~gu?`RewztA z1cO8*h9GGR{``zPp9t6vZJ81Ar<-bz38Jv-ro`wI#Mq&-k$*5tL<>Pk=)T1H_z8YhPJDWCuq5c#f&iDRo3$~XHhc-#T3{whJvB?;N^IKpX^H#=oYNa@u&^9He20t za7qlYKRH^S(Tj2{XC=lPI|MVMOVVX4V8cbx(9Ix%YK__iyN9E(k)118*aO-OzZNT# zbhE^f=Cze>bdhX>8xBFW70+=Tb@QnIyKKmQGt`}ZHXrVVWgxIT1k&eFDonM5iFh{^ z;FtT_qYo%x6$`ChDD~;i`c>h@T~X~pZ&-v==wrV4)ra@?=39Z}7c)OR&&9#@9uxU( z?hh)jyY_o}tH;1B>v%95XoGM@gDYB{I@;aJAn;N$2z~uDX|IL`uf-*Mm1ic21|E8c zQZWw`gvb==bz|iv=774j$zii$vlW@T4LDFEfea$Z+frqVA{<)qP_mhp2AbFqEE(0z zfCJgi{n&vKxpSY#-W)(E-Y3u@1KQGcnWN=qz;Nz2-6>bIL8wZk?oy8xe49zo9Evpm zI>QVA&&4C5*aCjxksX%9lfPpQNw|#TzMQ;YvC%Rx=uA#dmU{e@tzaW&rq}9N5VXBw z6Mff^1He^5U}j4TZD};Z7u2!LZ@OjGIPgR|MLZ*9%)E@0nE%K=W5s+NOT~n_{fBc9 z8DlU6un9om`MN~!FtpPXkJSq(+KPHqF&N23_vGeqphc*cEAF=okHGoFWHHWTm&R zAZXR)=q}Jv`jsvKCoL27h?ylNq0fz5xasR{P`5RW_7kzL^b_#T@e?r5nGKuMX?!lz zcEq|hYJscWj{YtO1of8Xi0jH z6s+!rS0;ag(Cml~|NKB+tNwwq9kl+8wc0!T$L$CFw95drNPiuZ3jOf4G_NXoM$sQj zZn*2v3^ISC(OoqO%W>m};%SHDOcD)D7%f&?jnrI9&1_u;6m(x2g#=wb zH$Cl!I6f#QI6iFo2i^nPy^8_Rt0g@Gzv3FoK629)r#wPie#!P^T*B)9JDi>Qta-Ee zyLS}t0#vL+3WcNfUo47o=g+h7Q(waq$0Fo`#^t+!ugP{n=lV`j6a9^vBl)I!L&VaI zK(10FWw?KM*=_ynJ3HIwyD^##=aKUk4u|yIYk$&C>^B?x{I5c+Il`m3RQ%_=Tq`!D zQw3HQ7dw%VR~rkqeqr+THi``YT){njI8j~%3VNWBl3EUyQ zx>y&BaDTkwjg$12&1?kD`IcCB_?j~8XMfHm4iQ(TCj7-)DOn-+%UzP)ab?nnNlfTA zh(FmGsK1tl`G8>eb=1j~9lDZPh<*?zhjW@Gx5%UjcH4 zbrrd<#%%JyFrW`_Loz= zP30^V%kIB;=&%K@{YbXT6@(|c>dXlNk~?15SVEmMX6`Mjv>+MN2M$^N?ju|1T-qoW zJQV;x5rIpTc>eCM*`;fq^U3U2uW>l1RVxe^4B$CEub2J}+bN)$=(gE92((ah@ar_) z+I|k<9;iL6@Dyhc+LX|pTR>r3{P!==s^guY!a#cZ5Ry6QtTzvk zUh~+ICB=TnC(!+~G1}X`=zKbJF=VNy60Le=gO@j5lEJet5>jc!PbM+D!ZlS$KuYx&pkm{S?k)BU1<65@ z({=ySGqzCiV-vc5qOJ z48y)rR(Ys{uWIjyQX*o`4?xK$K9nE1K!t$coI~(ku$IzWaVM`ocnY1)=&_o_R%I_2 zZ_{Cs>@7#7ktZS)0EENs++_HHh39c*#7z#Pyifk3+e!lsET`nm%a#Zp{hflp4Vw$+ zOju*)#0tN99xzE1;G}_c;Oj@<_%Z8;SCB3P74uOYE__wpp<3HB0g0wsxZ1toEwg)5 z23F}NQwRV%3UQi)GQQt^$a%zzV8w>aIl;CkQ!6h%=n!jXPZ;sfULBWNTi1QT%V~R| zdrjBQt+%&EcrjOO0&pO(SR|R1%nis?Q}KUl75Q=`bI5TGenEMls+QNXGp;Grr-EZVy`f(ovFSmI(u6D90n zU}rWOG+9F)ioe9yO)lx~AD<~|_xP=uVs4I z6w+kccIU+(Ltf0bDM$mvJrBdPzjnQ4w#L-qTZ+S6V5l=pqj|%(!m@K!R(Sm5G<;5V zXK~r#d34;M-;>*+VXbyWbw`4vdOanA^uK`Ag&w)G;7}_OpATxWe^GjFe%&*Ocx)w7 zwt4Bs4luF3C-9V+n~E!?(W3d6$CtEn7OZ{~I`6iW|1x;QzkF49GF&d=Wg#fC2^Vn?KLfW@n~pFc4gBpg!U$uFR0 z6`f||PCJat3glNlwW|z^j;^p%9oQc82S&N+!L>xWR*UT~JbFCj)0}2J6c-rV3iVO! z`IdFp zB0H{SvHRu;zx(EM(0%j9fA`HVZ|@5Oo0EGok@w*1K*{Sg3QERYynQ|7kzI{t_?~>T zQGQ|?TPR(EZYAFen;>d7>k zc`O4jwao>J?dp~fG@8l|SBHzOE5h7?Ba_OYs%93|;KP${8}j%VGb?LRi<;yffk06& zmc)TH`g@-+zt@fG!z|MO3057>Y}ppB{w8IS2o68)NnHSA-jKa+X$k+&Klw{5Ksly#ye_HBKV&h1zbIsIT-|0XRq)zWf_~s9{=n3BOfpPy7{f5RZzL^9tdzjj zr)R?-SV}4UX;&dWNKq={6q|g;FEbIjXC}?$K%uY_ur_MF+MkJ>-c@8l1|6F7^BR4N zf%t(1oJ!m zg^z<^ddW{6+A~!=F*1he)s`5=HR&3O@tjq)pn!{ zodn}X=d$=iUh-ibxQ>PQw|#fHTLppRwXG}*HyUkLKB?Vxf>#@2_z&V#B0Cjvmfka$ znI~k?Pp)A)OXy(kdOeH7nbmp9bNb|>|e%T7Dg>BKo&y=JzU)v zs{+P#O$)wko3MOQY!bv_78@Q%uABK!ZPIi<~iCxyQ>J*D53j_;0vks;+?UxqO^ z8)9k;>&t3F)oFofc_t(0cdCn(OIM;4fePgKSw+PKcigoQR9JV_C-y`&%By+|aMjTd z;$iN6>#`KNXtG+yNhfl+PYn(#cr;Nf>DZ1mRU`A-PFI}Scq~0EgRR31c4LZcz_w!3 zU&-x*oGPQoz`-m#bYEC;V<7tHiC(wn395M}YNU9p|6@2$$6(9N_DyMjuOwT6X&Cu> zXg1{_^+%NsBhDf;)3V~J5%bl|^XVjqRgu^moR2288%NOgcLoNBkN6t5F&l2`tPvao zfAbQy!&*Ln*uWc{tVDqwT1{Q>{s19S6+;c@2e$2eZd>zL~I~M}G^8w4Y2bnyq)>=S+L6j%|@%XWqbYm%+}R z%Jg=|X7Y&0*lujN6>tzy)?{CBuT|FT#I=sU+569+)8oyIH?8?{Y{Im(PMHAGs5_GI z>1wLl+yiE$+I28-c2!jx)_?k2nIm}7iH=O{X#yL$s@}hUPf^xece9Vi{DUPRKm%@= zI4q=C$Qla?I0{;1W!^-Bt)o=r>#KNZnZPW3piq_&q`~HLF~1_^MHlt66*62}BJqzu zM;g!LlycVJ?1ohPMvFHu3^-`<`sR(iyLG`EB|;bk%3GG!#?x`m5gx zWnZm7bb@UTrR9OXVs1t)?(5a%Yqq>?ivrob2S7W|CH$C|Kscw z=5hgFRsHTTA{lDQ(a0VW8vk$By+wL4Ao<5{Br)oU$x2pMfJKrlPqr@4P$Y9Nt_7R| zCx>hhMeHtjM0mJ|?T<(EIY{^^cAiA&R=2C=g&o@6vm!E&&86BrLOf18fr==x77OBH zdyOvB1fjqxDMa5;G9@=qu?tN_vB?)=#H^qB;g*jHrr^*ISGt+pLXyWcu+bAWNk&IG zl?zGxV&+)tmQ@d~T5Yypa4*^P5t*t6C($W-Y9zknsGLXPPDR^RF~`>QcV4iB%ltJg#%JgzSOl!L!d<7;Gfa5FAv zjVdBTD(TpZ3>zF8@VbIAM{aYtDv8fh>oAmOoV`*>G_abe#aOPM+6b%!IzPP2K{>A5U*>>2+^+79)a z;+jQ03qhGCNA7Yx7^lX9Ba9FuFHNen`s{buqNeEv)$x#QoePK6M~soRL17NVafu`4RB%F$`Pl z5~X9X{(zDkw(=x-=6pOllhfSrJCozywriAokKZ^VZ?epc?F2YfOmC=V98gW?oL=*# zC!4VJtdyAXwE6cHlNoijVy3KiZxeTrjL5AO4?|IT4#6gV63bUTC!(fd*MK@3^J@F! zOg&Y}^l`KyT>$RnH8O17_%?_PVh?o(+5L|_R7c|c+R_PRXb26L8QM&z+5MaH{wtOk zn}L=^TXs*WwrBLOJ6hDKim{LKAa3?WEiRefh;#TMZ3y1zA%QAUYh={Ux!GU!o~ zQNH$+pUp$BPoB27%q zF^6BflF{;t=SZSz+GrMJ3q~ti7gQ;5SbjS`5!DFxQB8KOt1OQ(G%_V;vcdj>K_dXjNxb}0M?HyjDs(afDCVx%>+I2GAO;jMfy0Iwh$=Utfm z5snMAm4|C3O1?MDEQ%I@RL1I{SrN67(Q)b*7k&Ip+-THJr%-;ILx=v!SaW75@EH3` zUhVOn4CYZ>iZ!iaGNBq9Be`Mcq5Opf?{HZfcJM-VDr$qSCy^3Lij|O&UW{&ffZ&!( zaA9$H9_5lFs;vRx6|mmn{Ic~u%y*(_t~*m12^>%iUOQ9Ap<@`U;!iRpBZ5y=p}@B6 zSP;R6QS{hs7)q75Mgj7814d~Bae=<{A1Z5>;LN66N?m?;5pl?`*_wW1l4a8IBb4tyR6@^@^BOm`{tD6YyAv};)Te2G+K}4;<~T9 ztiHbWTlGjD1=omQ_viT9PJOR7GjZ^{`7u?a_$hGpx54G9Z4Uj-NJ+>3SA0ZSx1vXw zLxYWusP2Sm*#o~_#B)vb&lTfmtsonTnPHIvx!#}HYvp=bPcZe zcHOCWuo0{MxR+#P#Pz1PSlaT$g-HbB!hTlHpV_F!Ay^U-vb1-6W)!xh?3imeOv*Z3 z=D=Ij-4e>!J=_Q#nqT5Fkomgv(@3uQo!?=8R9Sw(0)&ni z2jsV8*xm^OAO91C)$^*!X=%ZHvh_G35URQ9mZ|{A0)E?gJcL0T$H-NA92s6VF$CYW z9RHBse3R!V%B}9#+)P1_9L@j@2VcH-GZ=N2{$k05r?kj$KxpvthW zd7m|F4Ka%sEOHJC`oN z{Q9h2$S$VYkMHBEw7ybMx&7`nIaMLI5n~s)u5f7_tg^|2p4eFF&|6C45|-}T zY2bbCicJ7u0b>nvzMSvbBTOChoOAKvC$b5)Y}lT;{a-@oZBJ!oQNfsC36M4qtjvVR zX;Qkn$Pw56!sOMyw2f6>a4-#^ zy$1D*lt}-KofQ^atUig?;uYP;un=4nq7RPpS6+7^7eT`a+9Hs&(5Wu`IyLv0kJINP zH{2$kHb`Me^3C!975F7KG!qcJ%Ot-tp1f*bJffu1KR9B1lQ=XYBq15?hlJ33*QN-~ z25i$#OI}x{k+-P3EKo3v2XVk4?t;KE4nj1dk!Zo@w6D?!o#k^~T|3?;an*{_dc}rZ zWWWrKbdBu0k$7Zn5A%~0$lei$vU1P?CE&!L*!t%`ziuxu= z$+Xt=qUvFYn;a&JSK-D!mWnDWtF|5q!R|hT$Hv!*O-Hv$ zFMd5*W#~$3AJN-2|IVd@2bWN6TIfD_0uz(~vS50vn&4k2seimRF5`Q+1IS}!NNHN| zuWuQz50#5kO>f(wTSg+{VKXLrOZR$Gm~DhS1f%%-9{FGG$s*ZrqKZL|g5VaRU11N3WB;tGWJx5jj1rPZ1}$YE7~gsu zE25FmauDeN0tjmI!T8LA_@Jktp-r4gQRI3~pz@ext*^u56U%RNNACtB2^N&i&Zkq_ z`%gV|mr`$f?Rog-De|tRlA$9w&gIG-7Zqk}`K~S#ez0!r0TA4$*?1vW^S1eRHim+x~x!Fuo?ZZGGykdj`C(v!pIX!M7^#v%t*g zcznI+6jSi4g8knZOJ2XD^*-Nu8++1xNL67@Dpa}id>w3=oC<2l|TauHqSGbyr z9Lb=M3fe$ymZM2IcIy2$WhWPLfA8YEy!~$2XHICgk})!EbwTa@re-=DC1|8#7fNFq6gJ2K}GKAX`f_@q32jY5x4yTSxUH;`}j*L?c8b@JA9D(4X1n>r5 zmjA{5zUzqX9?77@2f4TGSC#Gv z>RXD%m8Sx#GLz`?10nyLA3f`rKtm)2mp8 z2WUMD#ZK*6rx@tHUO&Z&$15&*p$9S&RarVs7nI?jWCTx!i z0n`(39&^Y>ScN)8+_K-B#JBi}jEM2qqgbCqWKx*4*ll_rs)9n)b|4=f&23 zGJ5Ub{5j_`P?1;gHXtz{3VvNPjI4v63M z7VR-O|JQRM-E&ZagmZ6Y#+`oTU{Zdpg*T>rA?e2lXyimlx-MsB_vpS!^2jDQhm%@q z{n8XwoaYQc8y7Itb%2)$a=$~0tev`)%-s+AXZ8I@XV4DuPx#4Z3^R?1Q&1e*!{+@j zwy0-{m|^s)xqlSU>jQk{owo@5+inF)-p_24DlAw`pUe~G8ATB<-h>G97|FK_kfkQlN-!Xir7CB=dF)cJj`)++W>CeZ z0KpG5Ul%&-7q_N%mRtvtM37+jS>A#7p`RadxDFCIFsAEA)28 zRc#)^^3Z1>`W_P8_n+_5l5pGfayTk_=7^k}d#ir!c>8mR4k$J+> z7$;sN^3k#e1A<-CaO6F6V7^1u(puc4hVnfPK2u$wSE_XF>^Bp?OAv{2Y8)b{(a(2LFQfe!w)T1x>k{ZpuhTF(Y6rhpZbrH!ElxM! z5seXw{2(-vFEyNn8P2QzldxYgR;$=9Va+n>oR-HQXL;u7|E|m|OuX!t) z=Y4P{a-kdSJHXaCvpi=8=DW$Bomevgq&Ys4T71MX_~k_QpcOJ7j|>5e z8fKax8KCNY#00?1+;-F_`mYl6?wiA0M9-%AWH7g{~~uALu>r1q7;w|*!aJIeE{mR8WtR@KBhs8TcC2jA=CW|Xy-ycIi>d)c7Okmo?_;IS6kWJ z(`FLRj~hxiQw>hGi`}`RB+q+jpRWZ9z114q7dyj#>yMG?n=NfcSz}CGOi5Bt#D4u( zFREX`PCs3=cqxne=H=$udT;=|-YI7ij;hPlH)3oXm z`Zikh-OIS^*V9YKw;%r4iW?YA#ppM%LKP=jnMYQ)JEBqy1t4U@E<8VwMW2U*KvaS5 zNDwVyHjTg6hvcbS>{N7lJu=~^Ut)S#sq~v9%#hIV2H~>o^9=!kEGypac0E4e6TQIW zr~+Bn`Sb4k*0*Zts;f;Vq@fsZn1hLBQyIO8W(13u0211vHK)RMC5neH4xx7?6jMVOl3i-ENH1NU{ z-FW1hXwfmWi;TOg`k_dSL1ckNlukjE5IiKg=2DaEcWG#qTCd+ts`vavz;Wye>fPE6 zy5Y~H#6~R#r29XgZcKEUWF`#TkPjT0Tb$nr`$rM*rO!0=z{AwY-%*%Y>1iy07;xo= zlqRRR7Oc25bnNStf}IG@3`}b^k0oTD!zg(19YJjRnXs}9jracK>Fw6_hgpNk9M$d_ zY;%@p@*94vn6~^S;rS|c_SBN9%41Y5CNDz~xgJ>zs5bOlC^*0Hm`3d+UdEAQlhAJ~ z9rS!JpiEjf-g5TxWc*_}=Uu;kRBG#hg)R{HVt_KfnWZwXW)vK%qN^F`Uk1yRWlJX^%Xv zrk4pFBKoY0c4V8}-7;k5jeHn#no6bE=CpUiQ*YjAXr&^e4Ji=kd5l#`F`6lq$7V{v z3HxGM@4$C!_rCJ0-}}J#b+>i@#M5T@ zDq!my3QKfc?}%tQt*O2KZN233YvPN6nJ}^KNmAv>Z%4u&!~ecZRVXA}Vl6Juc1QC% z^+u0V1RbM%wwc6J;|v%G|8k{t}#XaV3b2aS>;{E0?a{QN?D zjap1}Foj*+4gOfLe03+j+-fGX6EVmh%q%{kCs18^=Y$ttM`Ru~Sih(@mxvo*(|OHJwq(zE2(ex%#gkzo*Y14gL&0 zb&R`Soa5K^wB%jo6cc>zQGL@J1IWOVy&G6nrZ5tClv8t|5cv^+Gb2^+T0kC3kdVb= zzt>d9Y8%qhJjVP{A;^*2E;@stxE=CCM8#hlN3jEzVQ}z~l*fFX-3jF?-%dnrKMp>* z+*ojsjy{>@Jvb5ZmHokSc4fmUNZRBEvkDd^(WV&AoGicLZM&xx+F?MzT8H=FtNK9| zS}XSejv}P(R*P5=IL)L^{d8bx{SC>9DDxXj4@z-n^Hya-p}k%LC>kvh2A}eK-{n8P z{ymeI^r5$}WuJ`hTT7y&m(wGugFoqC45jML$-|3L7JDo`mbG@4AeOa9^F5Xfc~AdJ z6z*HExRMYeE;qZsGE(eCPFCa$fMk$Uzn)5Lqpt$(K3(+J)whl&sJ0{&+hDO7rV zmH=Vx#~{t)BZI;GL9NP4eoCJAPi}V8s2_pM0^Qn!dLjeT+!j52$p%MSaS9-1=VIXE zZZI?CV3-Z~UNNk|?P_bEXiaFvcS$(=j(imNA_Txz*qk*3Zt> zNTsgN3vU6G(NEuWibkSSE-gZ&wr@}`tuvHEIJGFQY)vT7_Sn%Zf>;noCdR{II*9Uy zi1DPT!QZt9edc?XCO_%vF)Vha6tK-jiPV+wdZr2-8Z+moIE4fA9Um2wrmprd`ujDw zA4$!<#8*6C%(UP!wX!r@9XeCS{UX~rhBT6- z&m5@`REID~K)qRRLN40)>Fz=?P=C-jXZA1}lMo#Lic@|(zYtC?Sr$}gjz;wX-)dH; z>kQvsjFQ|FEvL5r4GE`Vi>HJ+qxMkQH`jx)M#C81t{fBmVaUEu2p_>}$^Lp*OiKYZg_C_ycw2+?0OT`)la$oyQwx zn_edD@HInp4-Gny;i{I~SnCp_RpFSS_!Eo_CI3DYHotlBCu`)~d17BV58M;K#oqAY zMpX+Xw9;xj#wpOozs(lT<+Th^5&14m(|Q*%;z`vKh4SNgAVBe}N~g2sLPrFC2|fE< zFpnnM-xp>{8@7DssTYKd@0S%KXilVkqrjiHGyiM<4X=4ToUoPe$O?bRyn$W!y*w+D z6&Dp2t9Ct*jrJO53Vv$UzniUP=-;pr=_NhmXKlFLRkmbSfW7QwHhvWb87Y|_ zx8ovSSXKm9h{zGnW$Hh-iI?ZMHSbjn*3Sh{-$#hX$;rQovTb9bL)q_$Wc zZmKiDhCM5p5vXSn($(MVPz`Tl^8Dq9O!MXzxdIh}Yi;I?zh>o(TXxwNlF}fbbJWC- z#GcWxTx796z)2UUjk&XWZFb3^oh-r)7Kkx{urkexT2D1!HLjPN~zvz2X#hz4#kSWLV*CW#DJu#do;exLU5E*Yb2H*HhXE&}5w)`L0O>xl{F?nRCT2 z*sv_q70&aZdR}eGSdA;#MccWyIlME%-v<$!Uv*^qnA&%(krwShZthK$iyit6H#l;> zK-^@!-w;mtEMfj7rnxx}?MKV=JHn^z-cHiGPN(d-mV0j(9hnwwg#l4%su_AWn&D=e zjR-cx9)55a@TwJcUi!8R@A2vD&T99g^diZcn-!n?8)u3269>8(cQRcMciiUGO^eip z5B)0E8kXbcz#sx*&|^TUl$Lb)lb&Ip>#TdtDfUcwzE~nzmuQ7EmTjAgdgUiGuSuNa zpCb6rE6(O5o(^pW-+RuE)g@nrZK=PFeQcL58r8o>9J$FQ<9+2A1d*DBdQ!b*dT;;4 z$Xo4EWN=S2^E$tAy9hSL=6Vn#bHD2g;0=sNhjJ6d)KUocZ)+A6o6_A*qTK}$*h#RS zyk#XkuOO@^1ht8v-%9N{Y9oewzu$e7L(scb^mXW2_TiW*-y)vNyH`OadIrI^Y>*Zd zp?=ROXFoq0Kk^tpwCFt$B)QKsZPM$&nJ*fs2;Xd)FtPd@FMUTnfVUp;sJHFaw;TuBTKR%BOW_}ClL_Bhz{A0l{Qgc%@tjIWj2ys8T z-56z(;=%E*LE!6!#2)6$>Eq4>1p;7`)Z_NSc1X=l%@0`gB7usIOR#p2{Cap%H#@u+ z`w+GL;VMer0DCjGMC|TGF_;&EgwZvSq=Q8@4}X7rF+n51h%CM@hl5WX$J z1a?I~km{+qh|RA-3+BNxgHjmg>KA!Bo!rA$QbB?cckI}KdkcLRox3JZd`fkXjx#A+ z_&En<1xc&Qmnoz0c*OV_guW?$J#uUHP(jS@beks0sZ#) z21ebzv6U?Wp@^S4Wn-$u_zmK3cE*C1Mlc5xAi|J_lu9>vY@H z+=VfBpk=&5g2V=pY;m2PHSN1`4hDAzs43VInEYm~-~S`AxRI%f?TU84wXtx z=s<1xk#OUIW)~ZG_2?E}ncAz?RlZ%Nu{wqJtc71aL~G>$Y^@Cl^I zh)|w&6EwGxERMm32{6|adN{lmCnO=?!|jUP3Ws1;e!SWGzjeq)Lvs!ZTTq&ie5vo- z`1p%Yqwt8KsRfc+Zbj`#L-1}(Bwi~Ax5qO&ZU@{ejQ+Hp4mt4VPoV_VeCr(6zF z9UR1ae&+2iX+s6E2V}Lxc6ZM+-8S6$a@?&Cn^C~=sPX~d#JLm;5Qw1n%IW*&PBV?q z09O(5{}gEc5xG_jOowcjF=x4y(&YamY5r}Y`?S#80Bh&J&-}>XgL{roRVEZo{x*i~ ziq&;TCj2%^Ju@%&4lTnyhe)5-5PDrQb*+9kAHW!EOaiu61g8cl_=CS1bA@HjhP}H5 zEBJUSKy2WF;ua_T{{-d-8TdvHidCA`BXq&j4cFtL z^yXVy20#nD1@%y@Y5U4sF1MvXa8K;F7B|Z;gH>tspveGY5S|}@U_A#|Imi?6GS1f%=ROP|BEkV#WqVG3b_;n2 z;H#;^adfh%ovD>w5Gs4>tI$7iJW3x%2mWus`fl%IFZf2qhN?JgWZYM_WBdsAyZ9Ln zRkEUt($@b`?c4fgl`7mn2lzu)}t zF)QPs=rMRr?Dp9+=yMv@`)?NKswHtVMS+34S>A@W)D9NFirDEhF)P8UhG0LzO-*O0 zw~iYtAHX;-bhAs~r#R<26~a<=Te-BB1z_}yavF7s_X>@Au~8kI-fv?*ch&2-MEDeRpn$| zQs#J6{sP}E#c@zKLH{=n*1NNgxp^;34)cyq+y$_nMaXHdPefdQB&ZYuaBF&F+#jI) z5iI(HZ*=0~V#^Xg^oqt{LGBS3`Mzzz-b6=qrl1#6B|u? z)MRjg9LIM9!?@uFajP;=#Ssg@2~wUs91pUhTWF1+X;!z;#!7zZ!HA3(S&VVh0-H-7)D5Ez?jhb5*13LRK%!y+ z0JbakM=Tfr@d$}P-7SM{#QqrU2pOeg#laPR_u*ECoxGxwD+5qp7mJFAC4KD`kx<@y z!H-TwF(`nXfja!2zxynS|Kfw?Nv{=+iYwx~iR_4 zsDFPJT72Tn&;L~mWIpqIHR?q6{H5=03xogjIQ00LT=Sm?Yu??dTo^X%GTU3y3 z5U%wt^lQ~lI;@oqpCR=JSG?o&&sGC)JkTBL$iPQn)gVhj=u1Ww=)nAbnfA|CTF1W} zHDFT%X57(fTIQ+HQ=ZLM-4b?z)=H^8gSHr jqXrx`;HZHtT?79Qd=?ufS>7*000000NkvXXu0mjfyH5ns literal 0 HcmV?d00001 diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ov5640/ov5640.c b/src/port_stm32f7/common/bsp_drivers/Components/ov5640/ov5640.c new file mode 100644 index 00000000..605ff83e --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ov5640/ov5640.c @@ -0,0 +1,1306 @@ +/** + ****************************************************************************** + * @file ov5640.c + * @author MCD Application Team + * @brief This file provides the OV5640 camera driver + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "ov5640.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup OV5640 + * @brief This file provides a set of functions needed to drive the + * OV5640 Camera module. + * @{ + */ + +/** @defgroup OV5640_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @defgroup OV5640_Private_Defines + * @{ + */ + +/** + * @} + */ + +/** @defgroup OV5640_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup OV5640_Private_FunctionPrototypes + * @{ + */ +static uint32_t ov5640_ConvertValue(uint32_t feature, uint32_t value); +/** + * @} + */ + +/** @defgroup OV5640_Private_Variables + * @{ + */ + +CAMERA_DrvTypeDef ov5640_drv = +{ + ov5640_Init, + ov5640_ReadID, + ov5640_Config, +}; + +const uint16_t OV5640_Init[][2] = +{ + {0x3103, 0x11}, + {0x3008, 0x82}, + {0x3103, 0x03}, + {0x3017, 0xFF}, + {0x3018, 0xf3}, + {0x3034, 0x18}, + {0x3008, 0x02}, + {0x3035, 0x41}, + {0x3036, 0x60}, + {0x3037, 0x13}, + {0x3108, 0x01}, + {0x3630, 0x36}, + {0x3631, 0x0e}, + {0x3632, 0xe2}, + {0x3633, 0x12}, + {0x3621, 0xe0}, + {0x3704, 0xa0}, + {0x3703, 0x5a}, + {0x3715, 0x78}, + {0x3717, 0x01}, + {0x370b, 0x60}, + {0x3705, 0x1a}, + {0x3905, 0x02}, + {0x3906, 0x10}, + {0x3901, 0x0a}, + {0x3731, 0x12}, + {0x3600, 0x08}, + {0x3601, 0x33}, + {0x302d, 0x60}, + {0x3620, 0x52}, + {0x371b, 0x20}, + {0x471c, 0x50}, + {0x3a13, 0x43}, + {0x3a18, 0x00}, + {0x3a19, 0xf8}, + {0x3635, 0x13}, + {0x3636, 0x03}, + {0x3634, 0x40}, + {0x3622, 0x01}, + {0x3c01, 0x34}, + {0x3c04, 0x28}, + {0x3c05, 0x98}, + {0x3c06, 0x00}, + {0x3c07, 0x00}, + {0x3c08, 0x01}, + {0x3c09, 0x2c}, + {0x3c0a, 0x9c}, + {0x3c0b, 0x40}, + {0x3820, 0x00}, + {0x3821, 0x06}, + {0x3814, 0x31}, + {0x3815, 0x31}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x04}, + {0x3804, 0x0a}, + {0x3805, 0x3f}, + {0x3806, 0x07}, + {0x3807, 0x9b}, + {0x3808, 0x03}, + {0x3809, 0x20}, + {0x380a, 0x02}, + {0x380b, 0x58}, + {0x380c, 0x07}, + {0x380d, 0x68}, + {0x380e, 0x03}, + {0x380f, 0xd8}, + {0x3810, 0x00}, + {0x3811, 0x10}, + {0x3812, 0x00}, + {0x3813, 0x06}, + {0x3618, 0x00}, + {0x3612, 0x29}, + {0x3708, 0x64}, + {0x3709, 0x52}, + {0x370c, 0x03}, + {0x3a02, 0x03}, + {0x3a03, 0xd8}, + {0x3a08, 0x01}, + {0x3a09, 0x27}, + {0x3a0a, 0x00}, + {0x3a0b, 0xf6}, + {0x3a0e, 0x03}, + {0x3a0d, 0x04}, + {0x3a14, 0x03}, + {0x3a15, 0xd8}, + {0x4001, 0x02}, + {0x4004, 0x02}, + {0x3000, 0x00}, + {0x3002, 0x1c}, + {0x3004, 0xff}, + {0x3006, 0xc3}, + {0x300e, 0x58}, + {0x302e, 0x00}, + {0x4740, 0x20}, + {0x4300, 0x30}, + {0x501f, 0x00}, + {0x4713, 0x03}, + {0x4407, 0x04}, + {0x440e, 0x00}, + {0x460b, 0x35}, + {0x460c, 0x23}, + {0x4837, 0x22}, + {0x3824, 0x02}, + {0x5000, 0xa7}, + {0x5001, 0xa3}, + {0x5180, 0xff}, + {0x5181, 0xf2}, + {0x5182, 0x00}, + {0x5183, 0x14}, + {0x5184, 0x25}, + {0x5185, 0x24}, + {0x5186, 0x09}, + {0x5187, 0x09}, + {0x5188, 0x09}, + {0x5189, 0x75}, + {0x518a, 0x54}, + {0x518b, 0xe0}, + {0x518c, 0xb2}, + {0x518d, 0x42}, + {0x518e, 0x3d}, + {0x518f, 0x56}, + {0x5190, 0x46}, + {0x5191, 0xf8}, + {0x5192, 0x04}, + {0x5193, 0x70}, + {0x5194, 0xf0}, + {0x5195, 0xf0}, + {0x5196, 0x03}, + {0x5197, 0x01}, + {0x5198, 0x04}, + {0x5199, 0x12}, + {0x519a, 0x04}, + {0x519b, 0x00}, + {0x519c, 0x06}, + {0x519d, 0x82}, + {0x519e, 0x38}, + {0x5381, 0x1e}, + {0x5382, 0x5b}, + {0x5383, 0x08}, + {0x5384, 0x0a}, + {0x5385, 0x7e}, + {0x5386, 0x88}, + {0x5387, 0x7c}, + {0x5388, 0x6c}, + {0x5389, 0x10}, + {0x538a, 0x01}, + {0x538b, 0x98}, + {0x5300, 0x08}, + {0x5301, 0x30}, + {0x5302, 0x10}, + {0x5303, 0x00}, + {0x5304, 0x08}, + {0x5305, 0x30}, + {0x5306, 0x08}, + {0x5307, 0x16}, + {0x5309, 0x08}, + {0x530a, 0x30}, + {0x530b, 0x04}, + {0x530c, 0x06}, + {0x5480, 0x01}, + {0x5481, 0x08}, + {0x5482, 0x14}, + {0x5483, 0x28}, + {0x5484, 0x51}, + {0x5485, 0x65}, + {0x5486, 0x71}, + {0x5487, 0x7d}, + {0x5488, 0x87}, + {0x5489, 0x91}, + {0x548a, 0x9a}, + {0x548b, 0xaa}, + {0x548c, 0xb8}, + {0x548d, 0xcd}, + {0x548e, 0xdd}, + {0x548f, 0xea}, + {0x5490, 0x1d}, + {0x5580, 0x02}, + {0x5583, 0x40}, + {0x5584, 0x10}, + {0x5589, 0x10}, + {0x558a, 0x00}, + {0x558b, 0xf8}, + {0x5800, 0x23}, + {0x5801, 0x14}, + {0x5802, 0x0f}, + {0x5803, 0x0f}, + {0x5804, 0x12}, + {0x5805, 0x26}, + {0x5806, 0x0c}, + {0x5807, 0x08}, + {0x5808, 0x05}, + {0x5809, 0x05}, + {0x580a, 0x08}, + {0x580b, 0x0d}, + {0x580c, 0x08}, + {0x580d, 0x03}, + {0x580e, 0x00}, + {0x580f, 0x00}, + {0x5810, 0x03}, + {0x5811, 0x09}, + {0x5812, 0x07}, + {0x5813, 0x03}, + {0x5814, 0x00}, + {0x5815, 0x01}, + {0x5816, 0x03}, + {0x5817, 0x08}, + {0x5818, 0x0d}, + {0x5819, 0x08}, + {0x581a, 0x05}, + {0x581b, 0x06}, + {0x581c, 0x08}, + {0x581d, 0x0e}, + {0x581e, 0x29}, + {0x581f, 0x17}, + {0x5820, 0x11}, + {0x5821, 0x11}, + {0x5822, 0x15}, + {0x5823, 0x28}, + {0x5824, 0x46}, + {0x5825, 0x26}, + {0x5826, 0x08}, + {0x5827, 0x26}, + {0x5828, 0x64}, + {0x5829, 0x26}, + {0x582a, 0x24}, + {0x582b, 0x22}, + {0x582c, 0x24}, + {0x582d, 0x24}, + {0x582e, 0x06}, + {0x582f, 0x22}, + {0x5830, 0x40}, + {0x5831, 0x42}, + {0x5832, 0x24}, + {0x5833, 0x26}, + {0x5834, 0x24}, + {0x5835, 0x22}, + {0x5836, 0x22}, + {0x5837, 0x26}, + {0x5838, 0x44}, + {0x5839, 0x24}, + {0x583a, 0x26}, + {0x583b, 0x28}, + {0x583c, 0x42}, + {0x583d, 0xce}, + {0x5025, 0x00}, + {0x3a0f, 0x30}, + {0x3a10, 0x28}, + {0x3a1b, 0x30}, + {0x3a1e, 0x26}, + {0x3a11, 0x60}, + {0x3a1f, 0x14}, + {0x3008, 0x02}, +}; + +/* Initialization sequence for WVGA resolution (800x480)*/ +const uint16_t OV5640_WVGA[][2]= +{ + {0x3808, 0x03}, + {0x3809, 0x20}, + {0x380a, 0x01}, + {0x380b, 0xE0}, + {0x4300, 0x6F}, + {0x4740, 0x22}, + {0x501F, 0x01}, +}; + +/* Initialization sequence for VGA resolution (640x480)*/ +const uint16_t OV5640_VGA[][2]= +{ + {0x3808, 0x02}, + {0x3809, 0x80}, + {0x380a, 0x01}, + {0x380b, 0xE0}, + {0x4300, 0x6F}, + {0x4740, 0x22}, + {0x501F, 0x01}, +}; + +/* Initialization sequence for 480x272 resolution */ +const uint16_t OV5640_480x272[][2]= +{ + {0x3808, 0x01}, + {0x3809, 0xE0}, + {0x380a, 0x01}, + {0x380b, 0x10}, + {0x4300, 0x6F}, + {0x4740, 0x22}, + {0x501f, 0x01}, +}; + +const uint16_t OV5640_QVGA[][2] = +{ + {0x3808, 0x01}, + {0x3809, 0x40}, + {0x380a, 0x00}, + {0x380b, 0xF0}, + {0x4300, 0x6F}, + {0x4740, 0x22}, + {0x501f, 0x01}, +}; + +/* Initialization sequence for QQVGA resolution (160x120) */ +const uint16_t OV5640_QQVGA[][2]= +{ + {0x3808, 0x00}, + {0x3809, 0xA0}, + {0x380a, 0x00}, + {0x380b, 0x78}, + {0x4300, 0x6F}, + {0x4740, 0x22}, + {0x501f, 0x01}, +}; + +/* OV5640 Light Mode setting */ +const uint16_t OV5640_LightModeAuto[][2]= +{ + {0x3406, 0x00}, + {0x3400, 0x04}, + {0x3401, 0x00}, + {0x3402, 0x04}, + {0x3403, 0x00}, + {0x3404, 0x04}, + {0x3405, 0x00}, +}; + +const uint16_t OV5640_LightModeCloudy[][2]= +{ + {0x3406, 0x01}, + {0x3400, 0x06}, + {0x3401, 0x48}, + {0x3402, 0x04}, + {0x3403, 0x00}, + {0x3404, 0x04}, + {0x3405, 0xd3}, +}; + +const uint16_t OV5640_LightModeOffice[][2]= +{ + {0x3406, 0x01}, + {0x3400, 0x05}, + {0x3401, 0x48}, + {0x3402, 0x04}, + {0x3403, 0x00}, + {0x3404, 0x07}, + {0x3405, 0xcf}, +}; + +const uint16_t OV5640_LightModeHome[][2]= +{ + {0x3406, 0x01}, + {0x3400, 0x04}, + {0x3401, 0x10}, + {0x3402, 0x04}, + {0x3403, 0x00}, + {0x3404, 0x08}, + {0x3405, 0xB6}, +}; + +const uint16_t OV5640_LightModeSunny[][2]= +{ + {0x3406, 0x01}, + {0x3400, 0x06}, + {0x3401, 0x1c}, + {0x3402, 0x04}, + {0x3403, 0x00}, + {0x3404, 0x04}, + {0x3405, 0xf3}, +}; + +/** + * @} + */ + + +/** + * @brief Initializes the OV5640 CAMERA component. + * @param DeviceAddr: Device address on communication Bus. + * @param resolution: Camera resolution + * @retval None + */ +void ov5640_Init(uint16_t DeviceAddr, uint32_t resolution) +{ + uint32_t index = 0; + + for(index=0; index< (sizeof(OV5640_Init)/4) ; index++) + { + CAMERA_IO_Write(DeviceAddr, OV5640_Init[index][0], OV5640_Init[index][1]); + } + + /* Initialize OV5640 */ + switch (resolution) + { + case CAMERA_R160x120: + { + for(index=0; index<(sizeof(OV5640_QQVGA)/4); index++) + { + CAMERA_IO_Write(DeviceAddr, OV5640_QQVGA[index][0], OV5640_QQVGA[index][1]); + } + break; + } + case CAMERA_R320x240: + { + for(index=0; index< (sizeof(OV5640_QVGA)/4); index++) + { + CAMERA_IO_Write(DeviceAddr, OV5640_QVGA[index][0], OV5640_QVGA[index][1]); + } + + break; + } + case CAMERA_R480x272: + { + for(index=0; index<(sizeof(OV5640_480x272)/4); index++) + { + CAMERA_IO_Write(DeviceAddr, OV5640_480x272[index][0], OV5640_480x272[index][1]); + } + break; + } + case CAMERA_R640x480: + { + for(index=0; index<(sizeof(OV5640_VGA)/4); index++) + { + CAMERA_IO_Write(DeviceAddr, OV5640_VGA[index][0], OV5640_VGA[index][1]); + } + break; + } + default: + { + break; + } + } +} + +/** + * @brief Set the OV5640 camera Light Mode. + * @param DeviceAddr : Device address on communication Bus. + * @param Effect : Effect to be configured + * @retval None + */ +void OV5640_SetLightMode(uint16_t DeviceAddr, uint8_t LightMode) +{ + uint32_t index = 0; + + CAMERA_IO_Write(DeviceAddr, 0x3406, 0x00); + CAMERA_IO_Write(DeviceAddr, 0x5190, 0x46); + CAMERA_IO_Write(DeviceAddr, 0x5191, 0xf8); + CAMERA_IO_Write(DeviceAddr, 0x5192, 0x04); + + switch(LightMode) + { + case OV5640_LIGHT_AUTO: + for(index=0; index< (sizeof(OV5640_LightModeAuto)/4) ; index++) + { + CAMERA_IO_Write(DeviceAddr, OV5640_LightModeAuto[index][0], OV5640_LightModeAuto[index][1]); + } + break; + case OV5640_LIGHT_SUNNY: + for(index=0; index< (sizeof(OV5640_LightModeSunny)/4) ; index++) + { + CAMERA_IO_Write(DeviceAddr, OV5640_LightModeSunny[index][0], OV5640_LightModeSunny[index][1]); + } + break; + case OV5640_LIGHT_OFFICE: + for(index=0; index< (sizeof(OV5640_LightModeOffice)/4) ; index++) + { + CAMERA_IO_Write(DeviceAddr, OV5640_LightModeOffice[index][0], OV5640_LightModeOffice[index][1]); + } + break; + case OV5640_LIGHT_CLOUDY: + for(index=0; index< (sizeof(OV5640_LightModeCloudy)/4) ; index++) + { + CAMERA_IO_Write(DeviceAddr, OV5640_LightModeCloudy[index][0], OV5640_LightModeCloudy[index][1]); + } + break; + case OV5640_LIGHT_HOME: + for(index=0; index< (sizeof(OV5640_LightModeHome)/4) ; index++) + { + CAMERA_IO_Write(DeviceAddr, OV5640_LightModeHome[index][0], OV5640_LightModeHome[index][1]); + } + break; + default : + /* Auto light mode used */ + for(index=0; index< (sizeof(OV5640_LightModeAuto)/4) ; index++) + { + CAMERA_IO_Write(DeviceAddr, OV5640_LightModeAuto[index][0], OV5640_LightModeAuto[index][1]); + } + break; + } +} + +/** + * @brief Set the OV5640 camera Special Effect. + * @param DeviceAddr: Device address on communication Bus. + * @param Effect: Effect to be configured + * @retval None + */ +void OV5640_SetEffect(uint16_t DeviceAddr, uint32_t Effect) +{ + switch(Effect) + { + case OV5640_COLOR_EFFECT_NONE: + CAMERA_IO_Write(DeviceAddr, 0x5001, 0x7F); + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x00); + break; + + case OV5640_COLOR_EFFECT_BLUE: + CAMERA_IO_Write(DeviceAddr, 0x5001, 0xFF); + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x18); + CAMERA_IO_Write(DeviceAddr, 0x5583, 0xA0); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x40); + break; + + case OV5640_COLOR_EFFECT_RED: + CAMERA_IO_Write(DeviceAddr, 0x5001, 0xFF); + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x18); + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x80); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0xC0); + break; + + case OV5640_COLOR_EFFECT_GREEN: + CAMERA_IO_Write(DeviceAddr, 0x5001, 0xFF); + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x18); + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x60); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x60); + break; + + case OV5640_COLOR_EFFECT_BW: + CAMERA_IO_Write(DeviceAddr, 0x5001, 0xFF); + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x18); + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x80); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x80); + break; + + case OV5640_COLOR_EFFECT_SEPIA: + CAMERA_IO_Write(DeviceAddr, 0x5001, 0xFF); + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x18); + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x40); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0xA0); + break; + + case OV5640_COLOR_EFFECT_NEGATIVE: + CAMERA_IO_Write(DeviceAddr, 0x5001, 0xFF); + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x40); + break; + + case OV5640_COLOR_EFFECT_BW_NEGATIVE: + CAMERA_IO_Write(DeviceAddr, 0x5001, 0xFF); + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x58); + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x40); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x40); + break; + + case OV5640_COLOR_EFFECT_OVEREXPOSURE: + CAMERA_IO_Write(DeviceAddr, 0x5001, 0xFF); + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x18); + CAMERA_IO_Write(DeviceAddr, 0x5583, 0xF0); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0xF0); + break; + + case OV5640_COLOR_EFFECT_SOLARIZE: + CAMERA_IO_Write(DeviceAddr, 0x5001, 0xFF); + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x06); + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x40); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x10); + CAMERA_IO_Write(DeviceAddr, 0x5003, 0x09); + break; + + default : + /* No effect */ + CAMERA_IO_Write(DeviceAddr, 0x5001, 0x7F); + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x00); + break; + } +} + +/** + * @brief Set the OV5640 camera Brightness Level. + * @note The brightness of OV5640 could be adjusted. Higher brightness will + * make the picture more bright. The side effect of higher brightness + * is the picture looks foggy. + * @param DeviceAddr: Device address on communication Bus. + * @param Level: Value to be configured + * @retval None + */ +void OV5640_SetBrightness(uint16_t DeviceAddr, uint8_t Level) +{ + CAMERA_IO_Write(DeviceAddr, 0x5001, 0xFF); + + switch(Level) + { + case OV5640_BRIGHTNESS_LEVEL4P: + CAMERA_IO_Write(DeviceAddr, 0x5587, 0x40); + break; + + case OV5640_BRIGHTNESS_LEVEL3P: + CAMERA_IO_Write(DeviceAddr, 0x5587, 0x30); + break; + + case OV5640_BRIGHTNESS_LEVEL2P: + CAMERA_IO_Write(DeviceAddr, 0x5587, 0x20); + break; + + case OV5640_BRIGHTNESS_LEVEL1P: + CAMERA_IO_Write(DeviceAddr, 0x5587, 0x10); + break; + + case OV5640_BRIGHTNESS_LEVEL0: + CAMERA_IO_Write(DeviceAddr, 0x5587, 0x00); + break; + + case OV5640_BRIGHTNESS_LEVEL1N: + CAMERA_IO_Write(DeviceAddr, 0x5587, 0x10); + break; + + case OV5640_BRIGHTNESS_LEVEL2N: + CAMERA_IO_Write(DeviceAddr, 0x5587, 0x20); + break; + + case OV5640_BRIGHTNESS_LEVEL3N: + CAMERA_IO_Write(DeviceAddr, 0x5587, 0x30); + break; + + case OV5640_BRIGHTNESS_LEVEL4N: + CAMERA_IO_Write(DeviceAddr, 0x5587, 0x40); + break; + + default: + /* Level 0 as default */ + Level = OV5640_BRIGHTNESS_LEVEL0; + CAMERA_IO_Write(DeviceAddr, 0x5587, 0x00); + break; + } + + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x04); + + if(Level < OV5640_SATURATION_LEVEL1N) + { + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x01); + } + else + { + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x09); + } +} + +/** + * @brief Set the OV5640 camera Saturation Level. + * @note The color saturation of OV5640 could be adjusted. High color saturation + * would make the picture looks more vivid, but the side effect is the + * bigger noise and not accurate skin color. + * @param DeviceAddr: Device address on communication Bus. + * @param Level: Value to be configured + * @retval None + */ +void OV5640_SetSaturation(uint16_t DeviceAddr, uint8_t Level) +{ + CAMERA_IO_Write(DeviceAddr, 0x5001, 0xFF); + + switch(Level) + { + case OV5640_SATURATION_LEVEL4P: + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x40); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x40); + break; + + case OV5640_SATURATION_LEVEL3P: + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x50); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x50); + break; + + case OV5640_SATURATION_LEVEL2P: + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x60); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x60); + break; + + case OV5640_SATURATION_LEVEL1P: + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x70); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x70); + break; + + case OV5640_SATURATION_LEVEL0: + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x80); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x80); + break; + + case OV5640_SATURATION_LEVEL1N: + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x30); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x30); + break; + + case OV5640_SATURATION_LEVEL2N: + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x20); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x20); + break; + + case OV5640_SATURATION_LEVEL3N: + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x10); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x10); + break; + + case OV5640_SATURATION_LEVEL4N: + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x00); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x00); + break; + + default: + /* Level 0 as default */ + CAMERA_IO_Write(DeviceAddr, 0x5583, 0x40); + CAMERA_IO_Write(DeviceAddr, 0x5584, 0x40); + break; + } + + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x02); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x41); +} + +/** + * @brief Set the OV5640 camera Contrast Level. + * @note The contrast of OV5640 could be adjusted. Higher contrast will make + * the picture sharp. But the side effect is loosing dynamic range. + * @param DeviceAddr: Device address on communication Bus. + * @param Level: Value to be configured + * @retval None + */ +void OV5640_SetContrast(uint16_t DeviceAddr, uint8_t Level) +{ + CAMERA_IO_Write(DeviceAddr, 0x5001, 0xFF); + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x04); + + switch(Level) + { + case OV5640_CONTRAST_LEVEL4P: + CAMERA_IO_Write(DeviceAddr, 0x5586, 0x30); + CAMERA_IO_Write(DeviceAddr, 0x5585, 0x30); + break; + + case OV5640_CONTRAST_LEVEL3P: + CAMERA_IO_Write(DeviceAddr, 0x5586, 0x2C); + CAMERA_IO_Write(DeviceAddr, 0x5585, 0x2C); + break; + + case OV5640_CONTRAST_LEVEL2P: + CAMERA_IO_Write(DeviceAddr, 0x5586, 0x28); + CAMERA_IO_Write(DeviceAddr, 0x5585, 0x28); + break; + + case OV5640_CONTRAST_LEVEL1P: + CAMERA_IO_Write(DeviceAddr, 0x5586, 0x24); + CAMERA_IO_Write(DeviceAddr, 0x5585, 0x24); + break; + + case OV5640_CONTRAST_LEVEL0: + CAMERA_IO_Write(DeviceAddr, 0x5586, 0x20); + CAMERA_IO_Write(DeviceAddr, 0x5585, 0x20); + break; + + case OV5640_CONTRAST_LEVEL1N: + CAMERA_IO_Write(DeviceAddr, 0x5586, 0x1C); + CAMERA_IO_Write(DeviceAddr, 0x5585, 0x1C); + break; + + case OV5640_CONTRAST_LEVEL2N: + CAMERA_IO_Write(DeviceAddr, 0x5586, 0x18); + CAMERA_IO_Write(DeviceAddr, 0x5585, 0x18); + break; + + case OV5640_CONTRAST_LEVEL3N: + CAMERA_IO_Write(DeviceAddr, 0x5586, 0x14); + CAMERA_IO_Write(DeviceAddr, 0x5585, 0x14); + break; + + case OV5640_CONTRAST_LEVEL4N: + CAMERA_IO_Write(DeviceAddr, 0x5586, 0x10); + CAMERA_IO_Write(DeviceAddr, 0x5585, 0x10); + break; + + default: + /* Level 0 as default */ + CAMERA_IO_Write(DeviceAddr, 0x5586, 0x20); + CAMERA_IO_Write(DeviceAddr, 0x5585, 0x20); + break; + } + + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x41); +} + +/** + * @brief Set the OV5640 camera Hue degree. + * @param DeviceAddr: Device address on communication Bus. + * @param Level: Value to be configured + * @retval None + */ +void OV5640_SetHueDegree(uint16_t DeviceAddr, uint16_t Degree) +{ + CAMERA_IO_Write(DeviceAddr, 0x5001, 0xFF); + CAMERA_IO_Write(DeviceAddr, 0x5580, 0x01); + + switch(Degree) + { + case OV5640_HUE_150P: + CAMERA_IO_Write(DeviceAddr, 0x5581, 0x6F); + CAMERA_IO_Write(DeviceAddr, 0x5582, 0x40); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x31); + break; + + case OV5640_HUE_120P: + CAMERA_IO_Write(DeviceAddr, 0x5581, 0x40); + CAMERA_IO_Write(DeviceAddr, 0x5582, 0x6F); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x31); + break; + + case OV5640_HUE_90P: + CAMERA_IO_Write(DeviceAddr, 0x5581, 0x00); + CAMERA_IO_Write(DeviceAddr, 0x5582, 0x80); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x31); + break; + + case OV5640_HUE_60P: + CAMERA_IO_Write(DeviceAddr, 0x5581, 0x40); + CAMERA_IO_Write(DeviceAddr, 0x5582, 0x6F); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x01); + break; + + case OV5640_HUE_30P: + CAMERA_IO_Write(DeviceAddr, 0x5581, 0x6F); + CAMERA_IO_Write(DeviceAddr, 0x5582, 0x40); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x01); + break; + + case OV5640_HUE_0: + CAMERA_IO_Write(DeviceAddr, 0x5581, 0x80); + CAMERA_IO_Write(DeviceAddr, 0x5582, 0x00); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x01); + break; + + case OV5640_HUE_30N: + CAMERA_IO_Write(DeviceAddr, 0x5581, 0x6F); + CAMERA_IO_Write(DeviceAddr, 0x5582, 0x40); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x02); + break; + + case OV5640_HUE_60N: + CAMERA_IO_Write(DeviceAddr, 0x5581, 0x40); + CAMERA_IO_Write(DeviceAddr, 0x5582, 0x6F); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x02); + break; + + case OV5640_HUE_90N: + CAMERA_IO_Write(DeviceAddr, 0x5581, 0x00); + CAMERA_IO_Write(DeviceAddr, 0x5582, 0x80); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x02); + break; + + case OV5640_HUE_120N: + CAMERA_IO_Write(DeviceAddr, 0x5581, 0x40); + CAMERA_IO_Write(DeviceAddr, 0x5582, 0x6F); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x32); + break; + + case OV5640_HUE_150N: + CAMERA_IO_Write(DeviceAddr, 0x5581, 0x6F); + CAMERA_IO_Write(DeviceAddr, 0x5582, 0x40); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x32); + break; + + case OV5640_HUE_180N: + CAMERA_IO_Write(DeviceAddr, 0x5581, 0x80); + CAMERA_IO_Write(DeviceAddr, 0x5582, 0x00); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x32); + break; + + default: + /* Hue degree 0 as default */ + CAMERA_IO_Write(DeviceAddr, 0x5581, 0x80); + CAMERA_IO_Write(DeviceAddr, 0x5582, 0x00); + CAMERA_IO_Write(DeviceAddr, 0x5588, 0x01); + break; + } +} + +/** + * @brief Control OV5640 camera mirror/vflip. + * @param DeviceAddr: Device address on communication Bus. + * @param Config: To configure mirror, flip, both or nothing + * @retval None + */ +void OV5640_MirrorFlipConfig(uint16_t DeviceAddr, uint8_t Config) +{ + uint8_t tmp3820 = 0, tmp3821; + + tmp3820 = CAMERA_IO_Read(DeviceAddr, 0x3820); + tmp3820 &= 0xF9; + tmp3821 = CAMERA_IO_Read(DeviceAddr, 0x3821); + tmp3821 &= 0xF9; + + switch (Config) + { + case OV5640_MIRROR: + CAMERA_IO_Write(DeviceAddr, 0x3820, tmp3820 | 0x00); + CAMERA_IO_Write(DeviceAddr, 0x3821, tmp3821 | 0x06); + break; + + case OV5640_FLIP: + CAMERA_IO_Write(DeviceAddr, 0x3820, tmp3820 | 0x06); + CAMERA_IO_Write(DeviceAddr, 0x3821, tmp3821 | 0x00); + break; + case OV5640_MIRROR_FLIP: + CAMERA_IO_Write(DeviceAddr, 0x3820, tmp3820 | 0x06); + CAMERA_IO_Write(DeviceAddr, 0x3821, tmp3821 | 0x06); + break; + + case OV5640_MIRROR_FLIP_NORMAL: + CAMERA_IO_Write(DeviceAddr, 0x3820, tmp3820 | 0x00); + CAMERA_IO_Write(DeviceAddr, 0x3821, tmp3821 | 0x06); + break; + + default: + CAMERA_IO_Write(DeviceAddr, 0x3820, tmp3820 | 0x00); + CAMERA_IO_Write(DeviceAddr, 0x3821, tmp3821 | 0x00); + break; + } +} + +/** + * @brief Control OV5640 camera mirror/vflip. + * @param DeviceAddr: Device address on communication Bus. + * @param Zoom: Zoom to be configured + * @retval None + */ +void OV5640_ZoomConfig(uint16_t DeviceAddr, uint8_t Zoom) +{ + int32_t res = 0; + + /* Get camera resolution */ + res = OV5640_GetResolution(DeviceAddr); + + if(Zoom == OV5640_ZOOM_x1) + { + CAMERA_IO_Write(DeviceAddr, 0x5600, 0x10); + } + else + { + switch (res) + { + case CAMERA_R320x240: + case CAMERA_R480x272: + Zoom = Zoom >> 1; + break; + case CAMERA_R640x480: + Zoom = Zoom >> 2; + break; + default: + break; + } + + CAMERA_IO_Write(DeviceAddr, 0x5600, 0x00); + CAMERA_IO_Write(DeviceAddr, 0x5601, Zoom); + } +} + +/** + * @brief Get OV5640 camera resolution. + * @param DeviceAddr: Device address on communication Bus. + * @retval Camera resolution else 0xFF + */ +int32_t OV5640_GetResolution(uint16_t DeviceAddr) +{ + uint16_t x_size = 0, y_size = 0; + int32_t res = CAMERA_R640x480; + + x_size = CAMERA_IO_Read(DeviceAddr, 0x3808) << 8; + x_size |= CAMERA_IO_Read(DeviceAddr, 0x3809); + y_size = CAMERA_IO_Read(DeviceAddr, 0x380A) << 8; + y_size |= CAMERA_IO_Read(DeviceAddr, 0x380B); + + if((x_size == 640) && (y_size == 480)) + { + res = CAMERA_R640x480; + } + else if((x_size == 480) && (y_size == 272)) + { + res = CAMERA_R480x272; + } + else if((x_size == 320) && (y_size == 240)) + { + res = CAMERA_R320x240; + } + else if((x_size == 160) && (y_size == 120)) + { + res = CAMERA_R160x120; + } + else + { + res = 0xFF; + } + return res; +} + +/** + * @brief Configures the OV5640 camera feature. + * @param DeviceAddr: Device address on communication Bus. + * @param feature: Camera feature to be configured + * @param value: Value to be configured + * @param brightness_value: Brightness value to be configured + * @retval None + */ +void ov5640_Config(uint16_t DeviceAddr, uint32_t feature, uint32_t value, uint32_t brightness_value) +{ + uint32_t value_tmp; + uint32_t br_value; + + /* Convert the input value into ov5640 parameters */ + value_tmp = ov5640_ConvertValue(feature, value); + br_value = ov5640_ConvertValue(CAMERA_CONTRAST_BRIGHTNESS, brightness_value); + + switch(feature) + { + case CAMERA_CONTRAST_BRIGHTNESS: + { + OV5640_SetContrast(DeviceAddr, value_tmp); + OV5640_SetBrightness(DeviceAddr, br_value); + break; + } + case CAMERA_BLACK_WHITE: + case CAMERA_COLOR_EFFECT: + { + OV5640_SetEffect(DeviceAddr, value_tmp); + break; + } + default: + { + break; + } + } +} + +/** + * @brief Read the OV5640 Camera identity. + * @param DeviceAddr: Device address on communication Bus. + * @retval the OV5640 ID + */ +uint16_t ov5640_ReadID(uint16_t DeviceAddr) +{ + uint16_t read_val = 0; + + /* Initialize I2C */ + CAMERA_IO_Init(); + + /* Prepare the camera to be configured */ + CAMERA_IO_Write(DeviceAddr, 0x3008, 0x80); + CAMERA_Delay(500); + + read_val = CAMERA_IO_Read(DeviceAddr, 0x300A); + read_val = read_val << 8; + read_val |= CAMERA_IO_Read(DeviceAddr, 0x300B); + /* Get the camera ID */ + return read_val; +} + +/****************************************************************************** + Static Functions +*******************************************************************************/ +/** + * @brief Convert input values into ov5640 parameters. + * @param feature: Camera feature to be configured + * @param value: Value to be configured + * @retval The converted value + */ +static uint32_t ov5640_ConvertValue(uint32_t feature, uint32_t value) +{ + uint32_t ret = 0; + + switch(feature) + { + case CAMERA_BLACK_WHITE: + { + switch(value) + { + case CAMERA_BLACK_WHITE_BW: + { + ret = OV5640_COLOR_EFFECT_BW; + break; + } + case CAMERA_BLACK_WHITE_NEGATIVE: + { + ret = OV5640_COLOR_EFFECT_NEGATIVE; + break; + } + case CAMERA_BLACK_WHITE_BW_NEGATIVE: + { + ret = OV5640_COLOR_EFFECT_BW_NEGATIVE; + break; + } + case CAMERA_BLACK_WHITE_NORMAL: + default: + { + ret = OV5640_COLOR_EFFECT_NONE; + break; + } + } + break; + } + case CAMERA_CONTRAST_BRIGHTNESS: + { + switch(value) + { + case CAMERA_BRIGHTNESS_LEVEL0: + { + ret = OV5640_BRIGHTNESS_LEVEL4N; + break; + } + case CAMERA_BRIGHTNESS_LEVEL1: + { + ret = OV5640_BRIGHTNESS_LEVEL2N; + break; + } + case CAMERA_BRIGHTNESS_LEVEL2: + { + ret = OV5640_BRIGHTNESS_LEVEL0; + break; + } + case CAMERA_BRIGHTNESS_LEVEL3: + { + ret = OV5640_BRIGHTNESS_LEVEL2P; + break; + } + case CAMERA_BRIGHTNESS_LEVEL4: + { + ret = OV5640_BRIGHTNESS_LEVEL4P; + break; + } + case CAMERA_CONTRAST_LEVEL0: + { + ret = OV5640_CONTRAST_LEVEL4N; + break; + } + case CAMERA_CONTRAST_LEVEL1: + { + ret = OV5640_CONTRAST_LEVEL2N; + break; + } + case CAMERA_CONTRAST_LEVEL2: + { + ret = OV5640_CONTRAST_LEVEL0; + break; + } + case CAMERA_CONTRAST_LEVEL3: + { + ret = OV5640_CONTRAST_LEVEL2P; + break; + } + case CAMERA_CONTRAST_LEVEL4: + { + ret = OV5640_CONTRAST_LEVEL4P; + break; + } + default: + { + ret = OV5640_CONTRAST_LEVEL0; + break; + } + } + break; + } + case CAMERA_COLOR_EFFECT: + { + switch(value) + { + case CAMERA_COLOR_EFFECT_ANTIQUE: + { + ret = OV5640_COLOR_EFFECT_SEPIA; + break; + } + case CAMERA_COLOR_EFFECT_BLUE: + { + ret = OV5640_COLOR_EFFECT_BLUE; + break; + } + case CAMERA_COLOR_EFFECT_GREEN: + { + ret = OV5640_COLOR_EFFECT_GREEN; + break; + } + case CAMERA_COLOR_EFFECT_RED: + { + ret = OV5640_COLOR_EFFECT_RED; + break; + } + case CAMERA_COLOR_EFFECT_NONE: + default: + { + ret = OV5640_COLOR_EFFECT_NONE; + break; + } + } + break; + default: + { + ret = 0; + break; + } + } + } + + return ret; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ov5640/ov5640.h b/src/port_stm32f7/common/bsp_drivers/Components/ov5640/ov5640.h new file mode 100644 index 00000000..8ccc5c3f --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ov5640/ov5640.h @@ -0,0 +1,205 @@ +/** + ****************************************************************************** + * @file ov5640.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for the ov5640.c + * driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __OV5640_H +#define __OV5640_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "../Common/camera.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup ov5640 + * @{ + */ + +/** @defgroup OV5640_Exported_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup OV5640_Exported_Constants + * @{ + */ +/** + * @brief OV5640 ID + */ +#define OV5640_ID 0x5640 +/** + * @brief OV5640 Registers + */ + + +/** + * @brief OV5640 Features Parameters + */ + +/* Brightness */ +#define OV5640_BRIGHTNESS_LEVEL4P 0x00 /* Brightness level +4 */ +#define OV5640_BRIGHTNESS_LEVEL3P 0x01 /* Brightness level +3 */ +#define OV5640_BRIGHTNESS_LEVEL2P 0x02 /* Brightness level +2 */ +#define OV5640_BRIGHTNESS_LEVEL1P 0x04 /* Brightness level +1 */ +#define OV5640_BRIGHTNESS_LEVEL0 0x08 /* Brightness level 0 */ +#define OV5640_BRIGHTNESS_LEVEL1N 0x10 /* Brightness level -1 */ +#define OV5640_BRIGHTNESS_LEVEL2N 0x20 /* Brightness level -2 */ +#define OV5640_BRIGHTNESS_LEVEL3N 0x40 /* Brightness level -3 */ +#define OV5640_BRIGHTNESS_LEVEL4N 0x80 /* Brightness level -4 */ + +/* Saturation */ +#define OV5640_SATURATION_LEVEL4P 0x00 /* Saturation level +4 */ +#define OV5640_SATURATION_LEVEL3P 0x01 /* Saturation level +3 */ +#define OV5640_SATURATION_LEVEL2P 0x02 /* Saturation level +2 */ +#define OV5640_SATURATION_LEVEL1P 0x04 /* Saturation level +1 */ +#define OV5640_SATURATION_LEVEL0 0x08 /* Saturation level 0 */ +#define OV5640_SATURATION_LEVEL1N 0x10 /* Saturation level -1 */ +#define OV5640_SATURATION_LEVEL2N 0x20 /* Saturation level -2 */ +#define OV5640_SATURATION_LEVEL3N 0x40 /* Saturation level -3 */ +#define OV5640_SATURATION_LEVEL4N 0x80 /* Saturation level -4 */ + +/* Contrast */ +#define OV5640_CONTRAST_LEVEL4P 0x00 /* Contrast level +4 */ +#define OV5640_CONTRAST_LEVEL3P 0x01 /* Contrast level +3 */ +#define OV5640_CONTRAST_LEVEL2P 0x02 /* Contrast level +2 */ +#define OV5640_CONTRAST_LEVEL1P 0x04 /* Contrast level +1 */ +#define OV5640_CONTRAST_LEVEL0 0x08 /* Contrast level 0 */ +#define OV5640_CONTRAST_LEVEL1N 0x10 /* Contrast level -1 */ +#define OV5640_CONTRAST_LEVEL2N 0x20 /* Contrast level -2 */ +#define OV5640_CONTRAST_LEVEL3N 0x40 /* Contrast level -3 */ +#define OV5640_CONTRAST_LEVEL4N 0x80 /* Contrast level -4 */ + + +/* Hue Control */ +#define OV5640_HUE_150P 0x0001 /* Hue 150+ degree */ +#define OV5640_HUE_120P 0x0002 /* Hue 120+ degree */ +#define OV5640_HUE_90P 0x0004 /* Hue 90+ degree */ +#define OV5640_HUE_60P 0x0008 /* Hue 60+ degree */ +#define OV5640_HUE_30P 0x0010 /* Hue 30+ degree */ +#define OV5640_HUE_0 0x0020 /* Hue 0 degree */ +#define OV5640_HUE_30N 0x0040 /* Hue 30- degree */ +#define OV5640_HUE_60N 0x0080 /* Hue 60- degree */ +#define OV5640_HUE_90N 0x0100 /* Hue 90- degree */ +#define OV5640_HUE_120N 0x0200 /* Hue 120- degree */ +#define OV5640_HUE_150N 0x0400 /* Hue 150- degree */ +#define OV5640_HUE_180N 0x0800 /* Hue 180- degree */ + +/* Mirror/Flip */ +#define OV5640_MIRROR 0x00 /* Set camera mirror config */ +#define OV5640_FLIP 0x01 /* Set camera flip config */ +#define OV5640_MIRROR_FLIP 0x02 /* Set camera mirror and flip */ +#define OV5640_MIRROR_FLIP_NORMAL 0x04 /* Set camera normal mode */ + +/* Zoom */ +#define OV5640_ZOOM_x8 0x00 +#define OV5640_ZOOM_x4 0x11 +#define OV5640_ZOOM_x2 0x22 +#define OV5640_ZOOM_x1 0x44 + +/* Special Effect */ +#define OV5640_COLOR_EFFECT_NONE 0x00 /* No effect */ +#define OV5640_COLOR_EFFECT_BLUE 0x01 /* Blue effect */ +#define OV5640_COLOR_EFFECT_RED 0x02 /* Red effect */ +#define OV5640_COLOR_EFFECT_GREEN 0x04 /* Green effect */ +#define OV5640_COLOR_EFFECT_BW 0x08 /* Black and White effect */ +#define OV5640_COLOR_EFFECT_SEPIA 0x10 /* Sepia effect */ +#define OV5640_COLOR_EFFECT_NEGATIVE 0x20 /* Negative effect */ +#define OV5640_COLOR_EFFECT_BW_NEGATIVE 0x40 /* BW Negative effect */ +#define OV5640_COLOR_EFFECT_OVEREXPOSURE 0x80 /* Over exposure effect */ +#define OV5640_COLOR_EFFECT_SOLARIZE 0x100 /* Solarized effect */ + +/* Light Mode */ +#define OV5640_LIGHT_AUTO 0x00 /* Light Mode Auto */ +#define OV5640_LIGHT_SUNNY 0x01 /* Light Mode Sunny */ +#define OV5640_LIGHT_OFFICE 0x02 /* Light Mode Office */ +#define OV5640_LIGHT_HOME 0x04 /* Light Mode Home */ +#define OV5640_LIGHT_CLOUDY 0x08 /* Light Mode Claudy */ + +/* Saturation */ +#define OV5640_SATURATION_0 0x00 /* Color saturation 0 */ +#define OV5640_SATURATION_1 0x01 /* Color saturation 1 */ +#define OV5640_SATURATION_2 0x02 /* Color saturation 2 */ +#define OV5640_SATURATION_3 0x04 /* Color saturation 3 */ + +/* Exposure */ +#define OV5640_EXPOSURE_LEVEL_0 0x00 /* Exposure Level 0 */ +#define OV5640_EXPOSURE_LEVEL_1 0x01 /* Exposure Level 1 */ +#define OV5640_EXPOSURE_LEVEL_2 0x02 /* Exposure Level 2 */ +#define OV5640_EXPOSURE_LEVEL_3 0x04 /* Exposure Level 3 */ + +/** + * @} + */ + +/** @defgroup OV5640_Exported_Functions + * @{ + */ +void ov5640_Init(uint16_t DeviceAddr, uint32_t resolution); +void ov5640_Config(uint16_t DeviceAddr, uint32_t feature, uint32_t value, uint32_t BR_value); +uint16_t ov5640_ReadID(uint16_t DeviceAddr); +void OV5640_SetLightMode(uint16_t DeviceAddr, uint8_t LightMode); +void OV5640_SetEffect(uint16_t DeviceAddr, uint32_t Effect); +void OV5640_SetBrightness(uint16_t DeviceAddr, uint8_t Level); +void OV5640_SetSaturation(uint16_t DeviceAddr, uint8_t Level); +void OV5640_SetContrast(uint16_t DeviceAddr, uint8_t Level); +void OV5640_SetHueDegree(uint16_t DeviceAddr, uint16_t Degree); +void OV5640_MirrorFlipConfig(uint16_t DeviceAddr, uint8_t Config); +void OV5640_ZoomConfig(uint16_t DeviceAddr, uint8_t Zoom); +int32_t OV5640_GetResolution(uint16_t DeviceAddr); +void CAMERA_IO_Init(void); +void CAMERA_IO_Write(uint8_t addr, uint16_t reg, uint16_t value); +uint16_t CAMERA_IO_Read(uint8_t Addr, uint16_t Reg); +void CAMERA_Delay(uint32_t delay); + +/* CAMERA driver structure */ +extern CAMERA_DrvTypeDef ov5640_drv; +/** + * @} + */ +#ifdef __cplusplus +} +#endif + +#endif /* __OV5640_H */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ov9655/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/ov9655/Release_Notes.html new file mode 100644 index 00000000..47226ecc --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ov9655/Release_Notes.html @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + Release Notes for OV9655 Component Driver + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for OV9655 Component Driver

+

Copyright +2015 STMicroelectronics

+

+
+

 

+ + + + + + +
+ + +

Update History

V1.0.1 +/ 07-April-2017

+ +

Main +Changes

+ + + + + + + + + + +
  • Update comments to be used for PDSC generation

V1.0.0 / 25-June-2015

+ + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • First official release of OV9655 CAMERA component driver
  • +

License

+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ov9655/ov9655.c b/src/port_stm32f7/common/bsp_drivers/Components/ov9655/ov9655.c new file mode 100644 index 00000000..e82d07f7 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ov9655/ov9655.c @@ -0,0 +1,859 @@ +/** + ****************************************************************************** + * @file ov9655.c + * @author MCD Application Team + * @brief This file provides the OV9655 camera driver + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "ov9655.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup OV9655 + * @brief This file provides a set of functions needed to drive the + * OV9655 Camera module. + * @{ + */ + +/** @defgroup OV9655_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @defgroup OV9655_Private_Defines + * @{ + */ + +/** + * @} + */ + +/** @defgroup OV9655_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup OV9655_Private_FunctionPrototypes + * @{ + */ +static uint64_t ov9655_ConvertValue(uint32_t feature, uint32_t value); +/** + * @} + */ + +/** @defgroup OV9655_Private_Variables + * @{ + */ + +CAMERA_DrvTypeDef ov9655_drv = +{ + ov9655_Init, + ov9655_ReadID, + ov9655_Config, +}; + +/* Initialization sequence for VGA resolution (640x480)*/ +const unsigned char OV9655_VGA[][2]= +{ + {0x00, 0x00}, + {0x01, 0x80}, + {0x02, 0x80}, + {0xb5, 0x00}, + {0x35, 0x00}, + {0xa8, 0xc1}, + {0x3a, 0xcc}, + {0x3d, 0x99}, + {0x77, 0x02}, + {0x13, 0xe7}, + {0x26, 0x72}, + {0x27, 0x08}, + {0x28, 0x08}, + {0x2c, 0x08}, + {0xab, 0x04}, + {0x6e, 0x00}, + {0x6d, 0x55}, + {0x00, 0x11}, + {0x10, 0x7b}, + {0xbb, 0xae}, + {0x11, 0x03}, + {0x72, 0x00}, + {0x3e, 0x0c}, + {0x74, 0x3a}, + {0x76, 0x01}, + {0x75, 0x35}, + {0x73, 0x00}, + {0xc7, 0x80}, + {0x62, 0x00}, + {0x63, 0x00}, + {0x64, 0x02}, + {0x65, 0x20}, + {0x66, 0x01}, + {0xc3, 0x4e}, + {0x33, 0x00}, + {0xa4, 0x50}, + {0xaa, 0x92}, + {0xc2, 0x01}, + {0xc1, 0xc8}, + {0x1e, 0x04}, + {0xa9, 0xef}, + {0x0e, 0x61}, + {0x39, 0x57}, + {0x0f, 0x48}, + {0x24, 0x3c}, + {0x25, 0x36}, + {0x12, 0x63}, + {0x03, 0x12}, + {0x32, 0xff}, + {0x17, 0x16}, + {0x18, 0x02}, + {0x19, 0x01}, + {0x1a, 0x3d}, + {0x36, 0xfa}, + {0x69, 0x0a}, + {0x8c, 0x8d}, + {0xc0, 0xaa}, + {0x40, 0xd0}, + {0x43, 0x14}, + {0x44, 0xf0}, + {0x45, 0x46}, + {0x46, 0x62}, + {0x47, 0x2a}, + {0x48, 0x3c}, + {0x59, 0x85}, + {0x5a, 0xa9}, + {0x5b, 0x64}, + {0x5c, 0x84}, + {0x5d, 0x53}, + {0x5e, 0x0e}, + {0x6c, 0x0c}, + {0xc6, 0x85}, + {0xcb, 0xf0}, + {0xcc, 0xd8}, + {0x71, 0x78}, + {0xa5, 0x68}, + {0x6f, 0x9e}, + {0x42, 0xc0}, + {0x3f, 0x82}, + {0x8a, 0x23}, + {0x14, 0x3a}, + {0x3b, 0xcc}, + {0x34, 0x3d}, + {0x41, 0x40}, + {0xc9, 0xe0}, + {0xca, 0xe8}, + {0xcd, 0x93}, + {0x7a, 0x20}, + {0x7b, 0x1c}, + {0x7c, 0x28}, + {0x7d, 0x3c}, + {0x7e, 0x5a}, + {0x7f, 0x68}, + {0x80, 0x76}, + {0x81, 0x80}, + {0x82, 0x88}, + {0x83, 0x8f}, + {0x84, 0x96}, + {0x85, 0xa3}, + {0x86, 0xaf}, + {0x87, 0xc4}, + {0x88, 0xd7}, + {0x89, 0xe8}, + {0x4f, 0x98}, + {0x50, 0x98}, + {0x51, 0x00}, + {0x52, 0x28}, + {0x53, 0x70}, + {0x54, 0x98}, + {0x58, 0x1a}, + {0x6b, 0x5a}, + {0x90, 0x92}, + {0x91, 0x92}, + {0x9f, 0x90}, + {0xa0, 0x90}, + {0x16, 0x24}, + {0x2a, 0x00}, + {0x2b, 0x00}, + {0xac, 0x80}, + {0xad, 0x80}, + {0xae, 0x80}, + {0xaf, 0x80}, + {0xb2, 0xf2}, + {0xb3, 0x20}, + {0xb4, 0x20}, + {0xb6, 0xaf}, + {0x29, 0x15}, + {0x9d, 0x02}, + {0x9e, 0x02}, + {0x9e, 0x02}, + {0x04, 0x03}, + {0x05, 0x2e}, + {0x06, 0x2e}, + {0x07, 0x2e}, + {0x08, 0x2e}, + {0x2f, 0x2e}, + {0x4a, 0xe9}, + {0x4b, 0xdd}, + {0x4c, 0xdd}, + {0x4d, 0xdd}, + {0x4e, 0xdd}, + {0x70, 0x06}, + {0xa6, 0x40}, + {0xbc, 0x02}, + {0xbd, 0x01}, + {0xbe, 0x02}, + {0xbf, 0x01}, +}; + +/* Initialization sequence for QVGA resolution (320x240) */ +const unsigned char OV9655_QVGA[][2]= +{ + {0x00, 0x00}, + {0x01, 0x80}, + {0x02, 0x80}, + {0x03, 0x02}, + {0x04, 0x03}, + {0x09, 0x01}, + {0x0b, 0x57}, + {0x0e, 0x61}, + {0x0f, 0x40}, + {0x11, 0x01}, + {0x12, 0x62}, + {0x13, 0xc7}, + {0x14, 0x3a}, + {0x16, 0x24}, + {0x17, 0x18}, + {0x18, 0x04}, + {0x19, 0x01}, + {0x1a, 0x81}, + {0x1e, 0x00}, + {0x24, 0x3c}, + {0x25, 0x36}, + {0x26, 0x72}, + {0x27, 0x08}, + {0x28, 0x08}, + {0x29, 0x15}, + {0x2a, 0x00}, + {0x2b, 0x00}, + {0x2c, 0x08}, + {0x32, 0x12}, + {0x33, 0x00}, + {0x34, 0x3f}, + {0x35, 0x00}, + {0x36, 0x3a}, + {0x38, 0x72}, + {0x39, 0x57}, + {0x3a, 0xcc}, + {0x3b, 0x04}, + {0x3d, 0x99}, + {0x3e, 0x02}, + {0x3f, 0xc1}, + {0x40, 0xc0}, + {0x41, 0x41}, + {0x42, 0xc0}, + {0x43, 0x0a}, + {0x44, 0xf0}, + {0x45, 0x46}, + {0x46, 0x62}, + {0x47, 0x2a}, + {0x48, 0x3c}, + {0x4a, 0xfc}, + {0x4b, 0xfc}, + {0x4c, 0x7f}, + {0x4d, 0x7f}, + {0x4e, 0x7f}, + {0x4f, 0x98}, + {0x50, 0x98}, + {0x51, 0x00}, + {0x52, 0x28}, + {0x53, 0x70}, + {0x54, 0x98}, + {0x58, 0x1a}, + {0x59, 0x85}, + {0x5a, 0xa9}, + {0x5b, 0x64}, + {0x5c, 0x84}, + {0x5d, 0x53}, + {0x5e, 0x0e}, + {0x5f, 0xf0}, + {0x60, 0xf0}, + {0x61, 0xf0}, + {0x62, 0x00}, + {0x63, 0x00}, + {0x64, 0x02}, + {0x65, 0x20}, + {0x66, 0x00}, + {0x69, 0x0a}, + {0x6b, 0x5a}, + {0x6c, 0x04}, + {0x6d, 0x55}, + {0x6e, 0x00}, + {0x6f, 0x9d}, + {0x70, 0x21}, + {0x71, 0x78}, + {0x72, 0x11}, + {0x73, 0x01}, + {0x74, 0x10}, + {0x75, 0x10}, + {0x76, 0x01}, + {0x77, 0x02}, + {0x7A, 0x12}, + {0x7B, 0x08}, + {0x7C, 0x16}, + {0x7D, 0x30}, + {0x7E, 0x5e}, + {0x7F, 0x72}, + {0x80, 0x82}, + {0x81, 0x8e}, + {0x82, 0x9a}, + {0x83, 0xa4}, + {0x84, 0xac}, + {0x85, 0xb8}, + {0x86, 0xc3}, + {0x87, 0xd6}, + {0x88, 0xe6}, + {0x89, 0xf2}, + {0x8a, 0x24}, + {0x8c, 0x80}, + {0x90, 0x7d}, + {0x91, 0x7b}, + {0x9d, 0x02}, + {0x9e, 0x02}, + {0x9f, 0x7a}, + {0xa0, 0x79}, + {0xa1, 0x40}, + {0xa4, 0x50}, + {0xa5, 0x68}, + {0xa6, 0x4a}, + {0xa8, 0xc1}, + {0xa9, 0xef}, + {0xaa, 0x92}, + {0xab, 0x04}, + {0xac, 0x80}, + {0xad, 0x80}, + {0xae, 0x80}, + {0xaf, 0x80}, + {0xb2, 0xf2}, + {0xb3, 0x20}, + {0xb4, 0x20}, + {0xb5, 0x00}, + {0xb6, 0xaf}, + {0xb6, 0xaf}, + {0xbb, 0xae}, + {0xbc, 0x7f}, + {0xbd, 0x7f}, + {0xbe, 0x7f}, + {0xbf, 0x7f}, + {0xbf, 0x7f}, + {0xc0, 0xaa}, + {0xc1, 0xc0}, + {0xc2, 0x01}, + {0xc3, 0x4e}, + {0xc6, 0x05}, + {0xc7, 0x81}, + {0xc9, 0xe0}, + {0xca, 0xe8}, + {0xcb, 0xf0}, + {0xcc, 0xd8}, + {0xcd, 0x93}, + {0x12, 0x63}, + {0x40, 0x10}, +}; + +/* Initialization sequence for QQVGA resolution (160x120) */ +const char OV9655_QQVGA[][2]= +{ + {0x00, 0x00}, + {0x01, 0x80}, + {0x02, 0x80}, + {0x03, 0x02}, + {0x04, 0x03}, + {0x09, 0x01}, + {0x0b, 0x57}, + {0x0e, 0x61}, + {0x0f, 0x40}, + {0x11, 0x01}, + {0x12, 0x62}, + {0x13, 0xc7}, + {0x14, 0x3a}, + {0x16, 0x24}, + {0x17, 0x18}, + {0x18, 0x04}, + {0x19, 0x01}, + {0x1a, 0x81}, + {0x1e, 0x00}, + {0x24, 0x3c}, + {0x25, 0x36}, + {0x26, 0x72}, + {0x27, 0x08}, + {0x28, 0x08}, + {0x29, 0x15}, + {0x2a, 0x00}, + {0x2b, 0x00}, + {0x2c, 0x08}, + {0x32, 0xa4}, + {0x33, 0x00}, + {0x34, 0x3f}, + {0x35, 0x00}, + {0x36, 0x3a}, + {0x38, 0x72}, + {0x39, 0x57}, + {0x3a, 0xcc}, + {0x3b, 0x04}, + {0x3d, 0x99}, + {0x3e, 0x0e}, + {0x3f, 0xc1}, + {0x40, 0xc0}, + {0x41, 0x41}, + {0x42, 0xc0}, + {0x43, 0x0a}, + {0x44, 0xf0}, + {0x45, 0x46}, + {0x46, 0x62}, + {0x47, 0x2a}, + {0x48, 0x3c}, + {0x4a, 0xfc}, + {0x4b, 0xfc}, + {0x4c, 0x7f}, + {0x4d, 0x7f}, + {0x4e, 0x7f}, + {0x4f, 0x98}, + {0x50, 0x98}, + {0x51, 0x00}, + {0x52, 0x28}, + {0x53, 0x70}, + {0x54, 0x98}, + {0x58, 0x1a}, + {0x59, 0x85}, + {0x5a, 0xa9}, + {0x5b, 0x64}, + {0x5c, 0x84}, + {0x5d, 0x53}, + {0x5e, 0x0e}, + {0x5f, 0xf0}, + {0x60, 0xf0}, + {0x61, 0xf0}, + {0x62, 0x00}, + {0x63, 0x00}, + {0x64, 0x02}, + {0x65, 0x20}, + {0x66, 0x00}, + {0x69, 0x0a}, + {0x6b, 0x5a}, + {0x6c, 0x04}, + {0x6d, 0x55}, + {0x6e, 0x00}, + {0x6f, 0x9d}, + {0x70, 0x21}, + {0x71, 0x78}, + {0x72, 0x22}, + {0x73, 0x02}, + {0x74, 0x10}, + {0x75, 0x10}, + {0x76, 0x01}, + {0x77, 0x02}, + {0x7A, 0x12}, + {0x7B, 0x08}, + {0x7C, 0x16}, + {0x7D, 0x30}, + {0x7E, 0x5e}, + {0x7F, 0x72}, + {0x80, 0x82}, + {0x81, 0x8e}, + {0x82, 0x9a}, + {0x83, 0xa4}, + {0x84, 0xac}, + {0x85, 0xb8}, + {0x86, 0xc3}, + {0x87, 0xd6}, + {0x88, 0xe6}, + {0x89, 0xf2}, + {0x8a, 0x24}, + {0x8c, 0x80}, + {0x90, 0x7d}, + {0x91, 0x7b}, + {0x9d, 0x02}, + {0x9e, 0x02}, + {0x9f, 0x7a}, + {0xa0, 0x79}, + {0xa1, 0x40}, + {0xa4, 0x50}, + {0xa5, 0x68}, + {0xa6, 0x4a}, + {0xa8, 0xc1}, + {0xa9, 0xef}, + {0xaa, 0x92}, + {0xab, 0x04}, + {0xac, 0x80}, + {0xad, 0x80}, + {0xae, 0x80}, + {0xaf, 0x80}, + {0xb2, 0xf2}, + {0xb3, 0x20}, + {0xb4, 0x20}, + {0xb5, 0x00}, + {0xb6, 0xaf}, + {0xb6, 0xaf}, + {0xbb, 0xae}, + {0xbc, 0x7f}, + {0xbd, 0x7f}, + {0xbe, 0x7f}, + {0xbf, 0x7f}, + {0xbf, 0x7f}, + {0xc0, 0xaa}, + {0xc1, 0xc0}, + {0xc2, 0x01}, + {0xc3, 0x4e}, + {0xc6, 0x05}, + {0xc7, 0x82}, + {0xc9, 0xe0}, + {0xca, 0xe8}, + {0xcb, 0xf0}, + {0xcc, 0xd8}, + {0xcd, 0x93}, + {0x12, 0x63}, + {0x40, 0x10}, +}; + +/** + * @} + */ + +/** @defgroup OV9655_Private_Functions + * @{ + */ + +/** + * @brief Initializes the OV9655 CAMERA component. + * @param DeviceAddr: Device address on communication Bus. + * @param resolution: Camera resolution + * @retval None + */ +void ov9655_Init(uint16_t DeviceAddr, uint32_t resolution) +{ + uint32_t index; + + /* Initialize I2C */ + CAMERA_IO_Init(); + + /* Prepare the camera to be configured by resetting all its registers */ + CAMERA_IO_Write(DeviceAddr, OV9655_SENSOR_COM7, 0x80); + CAMERA_Delay(200); + + /* Initialize OV9655 */ + switch (resolution) + { + case CAMERA_R160x120: + { + for(index=0; index<(sizeof(OV9655_QQVGA)/2); index++) + { + CAMERA_IO_Write(DeviceAddr, OV9655_QQVGA[index][0], OV9655_QQVGA[index][1]); + CAMERA_Delay(2); + } + break; + } + case CAMERA_R320x240: + { + for(index=0; index<(sizeof(OV9655_QVGA)/2); index++) + { + CAMERA_IO_Write(DeviceAddr, OV9655_QVGA[index][0], OV9655_QVGA[index][1]); + CAMERA_Delay(2); + } + break; + } + case CAMERA_R480x272: + { + /* Not supported resolution */ + break; + } + case CAMERA_R640x480: + { + for(index=0; index<(sizeof(OV9655_VGA)/2); index++) + { + CAMERA_IO_Write(DeviceAddr, OV9655_VGA[index][0], OV9655_VGA[index][1]); + CAMERA_Delay(2); + } + break; + } + default: + { + break; + } + } +} + +/** + * @brief Configures the OV9655 camera feature. + * @param DeviceAddr: Device address on communication Bus. + * @param feature: Camera feature to be configured + * @param value: Value to be configured + * @param brightness_value: Brightness value to be configured + * @retval None + */ +void ov9655_Config(uint16_t DeviceAddr, uint32_t feature, uint32_t value, uint32_t brightness_value) +{ + uint8_t tslb, mtx1, mtx2, mtx3, mtx4, mtx5, mtx6; + uint64_t value_tmp; + uint32_t br_value; + + /* Convert the input value into ov9655 parameters */ + value_tmp = ov9655_ConvertValue(feature, value); + br_value = (uint32_t)ov9655_ConvertValue(CAMERA_CONTRAST_BRIGHTNESS, brightness_value); + + switch(feature) + { + case CAMERA_CONTRAST_BRIGHTNESS: + { + CAMERA_IO_Write(DeviceAddr, OV9655_SENSOR_BRTN, br_value); + CAMERA_IO_Write(DeviceAddr, OV9655_SENSOR_CNST1, value_tmp); + break; + } + case CAMERA_BLACK_WHITE: + case CAMERA_COLOR_EFFECT: + { + tslb = (uint8_t)(value_tmp >> 48); + mtx1 = (uint8_t)(value_tmp >> 40); + mtx2 = (uint8_t)(value_tmp >> 32); + mtx3 = (uint8_t)(value_tmp >> 24); + mtx4 = (uint8_t)(value_tmp >> 16); + mtx5 = (uint8_t)(value_tmp >> 8); + mtx6 = (uint8_t)(value_tmp); + CAMERA_IO_Write(DeviceAddr, OV9655_SENSOR_TSLB, tslb); + CAMERA_IO_Write(DeviceAddr, OV9655_SENSOR_MTX1, mtx1); + CAMERA_IO_Write(DeviceAddr, OV9655_SENSOR_MTX2, mtx2); + CAMERA_IO_Write(DeviceAddr, OV9655_SENSOR_MTX3, mtx3); + CAMERA_IO_Write(DeviceAddr, OV9655_SENSOR_MTX4, mtx4); + CAMERA_IO_Write(DeviceAddr, OV9655_SENSOR_MTX5, mtx5); + CAMERA_IO_Write(DeviceAddr, OV9655_SENSOR_MTX6, mtx6); + break; + } + default: + { + break; + } + } +} + +/** + * @brief Read the OV9655 Camera identity. + * @param DeviceAddr: Device address on communication Bus. + * @retval the OV9655 ID + */ +uint16_t ov9655_ReadID(uint16_t DeviceAddr) +{ + /* Initialize I2C */ + CAMERA_IO_Init(); + + /* Get the camera ID */ + return (CAMERA_IO_Read(DeviceAddr, OV9655_SENSOR_PIDH)); +} + +/****************************************************************************** + Static Functions +*******************************************************************************/ +/** + * @brief Convert input values into ov9655 parameters. + * @param feature: Camera feature to be configured + * @param value: Value to be configured + * @retval The converted value + */ +static uint64_t ov9655_ConvertValue(uint32_t feature, uint32_t value) +{ + uint64_t ret = 0; + + switch(feature) + { + case CAMERA_BLACK_WHITE: + { + switch(value) + { + case CAMERA_BLACK_WHITE_BW: + { + ret = OV9655_BLACK_WHITE_BW; + break; + } + case CAMERA_BLACK_WHITE_NEGATIVE: + { + ret = OV9655_BLACK_WHITE_NEGATIVE; + break; + } + case CAMERA_BLACK_WHITE_BW_NEGATIVE: + { + ret = OV9655_BLACK_WHITE_BW_NEGATIVE; + break; + } + case CAMERA_BLACK_WHITE_NORMAL: + { + ret = OV9655_BLACK_WHITE_NORMAL; + break; + } + default: + { + ret = OV9655_BLACK_WHITE_NORMAL; + break; + } + } + break; + } + case CAMERA_CONTRAST_BRIGHTNESS: + { + switch(value) + { + case CAMERA_BRIGHTNESS_LEVEL0: + { + ret = OV9655_BRIGHTNESS_LEVEL0; + break; + } + case CAMERA_BRIGHTNESS_LEVEL1: + { + ret = OV9655_BRIGHTNESS_LEVEL1; + break; + } + case CAMERA_BRIGHTNESS_LEVEL2: + { + ret = OV9655_BRIGHTNESS_LEVEL2; + break; + } + case CAMERA_BRIGHTNESS_LEVEL3: + { + ret = OV9655_BRIGHTNESS_LEVEL3; + break; + } + case CAMERA_BRIGHTNESS_LEVEL4: + { + ret = OV9655_BRIGHTNESS_LEVEL4; + break; + } + case CAMERA_CONTRAST_LEVEL0: + { + ret = OV9655_CONTRAST_LEVEL0; + break; + } + case CAMERA_CONTRAST_LEVEL1: + { + ret = OV9655_CONTRAST_LEVEL1; + break; + } + case CAMERA_CONTRAST_LEVEL2: + { + ret = OV9655_CONTRAST_LEVEL2; + break; + } + case CAMERA_CONTRAST_LEVEL3: + { + ret = OV9655_CONTRAST_LEVEL3; + break; + } + case CAMERA_CONTRAST_LEVEL4: + { + ret = OV9655_CONTRAST_LEVEL4; + break; + } + default: + { + ret = OV9655_CONTRAST_LEVEL0; + break; + } + } + break; + } + case CAMERA_COLOR_EFFECT: + { + switch(value) + { + case CAMERA_COLOR_EFFECT_ANTIQUE: + { + ret = OV9655_COLOR_EFFECT_ANTIQUE; + break; + } + case CAMERA_COLOR_EFFECT_BLUE: + { + ret = OV9655_COLOR_EFFECT_BLUE; + break; + } + case CAMERA_COLOR_EFFECT_GREEN: + { + ret = OV9655_COLOR_EFFECT_GREEN; + break; + } + case CAMERA_COLOR_EFFECT_RED: + { + ret = OV9655_COLOR_EFFECT_RED; + break; + } + case CAMERA_COLOR_EFFECT_NONE: + default: + { + ret = OV9655_COLOR_EFFECT_NONE; + break; + } + } + break; + default: + { + ret = 0; + break; + } + } + } + + return ret; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ov9655/ov9655.h b/src/port_stm32f7/common/bsp_drivers/Components/ov9655/ov9655.h new file mode 100644 index 00000000..b509ee31 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ov9655/ov9655.h @@ -0,0 +1,157 @@ +/** + ****************************************************************************** + * @file ov9655.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for the ov9655.c + * driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __OV9655_H +#define __OV9655_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "../Common/camera.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup ov9655 + * @{ + */ + +/** @defgroup OV9655_Exported_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup OV9655_Exported_Constants + * @{ + */ +/** + * @brief OV9655 ID + */ +#define OV9655_ID 0x96 +/** + * @brief OV9655 Registers + */ + +/* OV9655 Registers definition */ +#define OV9655_SENSOR_PIDH 0x0A +#define OV9655_SENSOR_PIDL 0x0B +#define OV9655_SENSOR_COM7 0x12 +#define OV9655_SENSOR_TSLB 0x3A +#define OV9655_SENSOR_MTX1 0x4F +#define OV9655_SENSOR_MTX2 0x50 +#define OV9655_SENSOR_MTX3 0x51 +#define OV9655_SENSOR_MTX4 0x52 +#define OV9655_SENSOR_MTX5 0x53 +#define OV9655_SENSOR_MTX6 0x54 +#define OV9655_SENSOR_BRTN 0x55 +#define OV9655_SENSOR_CNST1 0x56 +#define OV9655_SENSOR_CNST2 0x57 + +/** + * @brief OV9655 Features Parameters + */ +#define OV9655_BRIGHTNESS_LEVEL0 0xB0 /* Brightness level -2 */ +#define OV9655_BRIGHTNESS_LEVEL1 0x98 /* Brightness level -1 */ +#define OV9655_BRIGHTNESS_LEVEL2 0x00 /* Brightness level 0 */ +#define OV9655_BRIGHTNESS_LEVEL3 0x18 /* Brightness level +1 */ +#define OV9655_BRIGHTNESS_LEVEL4 0x30 /* Brightness level +2 */ + +#define OV9655_BLACK_WHITE_BW 0xCC000000000000 /* Black and white effect */ +#define OV9655_BLACK_WHITE_NEGATIVE 0xEC808000008080 /* Negative effect */ +#define OV9655_BLACK_WHITE_BW_NEGATIVE 0xEC000000000000 /* BW and Negative effect */ +#define OV9655_BLACK_WHITE_NORMAL 0xCC808000008080 /* Normal effect */ + +#define OV9655_CONTRAST_LEVEL0 0x30 /* Contrast level -2 */ +#define OV9655_CONTRAST_LEVEL1 0x38 /* Contrast level -1 */ +#define OV9655_CONTRAST_LEVEL2 0x40 /* Contrast level 0 */ +#define OV9655_CONTRAST_LEVEL3 0x50 /* Contrast level +1 */ +#define OV9655_CONTRAST_LEVEL4 0x60 /* Contrast level +2 */ + +#define OV9655_COLOR_EFFECT_NONE 0xCC808000008080 /* No color effect */ +#define OV9655_COLOR_EFFECT_ANTIQUE 0xCC000020F00000 /* Antique effect */ +#define OV9655_COLOR_EFFECT_BLUE 0xCC000000000060 /* Blue effect */ +#define OV9655_COLOR_EFFECT_GREEN 0xCC000000008000 /* Green effect */ +#define OV9655_COLOR_EFFECT_RED 0xCC600000000000 /* Red effect */ +/** + * @} + */ + +/** @defgroup OV9655_Exported_Functions + * @{ + */ +void ov9655_Init(uint16_t DeviceAddr, uint32_t resolution); +void ov9655_Config(uint16_t DeviceAddr, uint32_t feature, uint32_t value, uint32_t BR_value); +uint16_t ov9655_ReadID(uint16_t DeviceAddr); + +void CAMERA_IO_Init(void); +void CAMERA_IO_Write(uint8_t addr, uint8_t reg, uint8_t value); +uint8_t CAMERA_IO_Read(uint8_t addr, uint8_t reg); +void CAMERA_Delay(uint32_t delay); + +/* CAMERA driver structure */ +extern CAMERA_DrvTypeDef ov9655_drv; +/** + * @} + */ +#ifdef __cplusplus +} +#endif + +#endif /* __OV9655_H */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/rk043fn48h/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/rk043fn48h/Release_Notes.html new file mode 100644 index 00000000..c970771c --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/rk043fn48h/Release_Notes.html @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + Release Notes for RK043FN48H-CT672B LCD Component Driver + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for RK043FN48H-CT672B LCD Component Driver

+

Copyright +2015 STMicroelectronics

+

+
+

 

+ + + + + + +
+ + +

Update History

V1.0.1 +/ 02-June-2017

+ +

Main +Changes

+ + + + + + + + + + +
  • Update comments to be used for PDSC generation

V1.0.0 / 25-June-2015

+ + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • + + First official release of RK043FN48H LCD component driver
  • +

License

+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/rk043fn48h/rk043fn48h.h b/src/port_stm32f7/common/bsp_drivers/Components/rk043fn48h/rk043fn48h.h new file mode 100644 index 00000000..b8319158 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/rk043fn48h/rk043fn48h.h @@ -0,0 +1,119 @@ +/** + ****************************************************************************** + * @file rk043fn48h.h + * @author MCD Application Team + * @brief This file contains all the constants parameters for the RK043FN48H-CT672B + * LCD component. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __RK043FN48H_H +#define __RK043FN48H_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup rk043fn48h + * @{ + */ + +/** @defgroup RK043FN48H_Exported_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup RK043FN48H_Exported_Constants + * @{ + */ + +/** + * @brief RK043FN48H Size + */ +#define RK043FN48H_WIDTH ((uint16_t)480) /* LCD PIXEL WIDTH */ +#define RK043FN48H_HEIGHT ((uint16_t)272) /* LCD PIXEL HEIGHT */ + +/** + * @brief RK043FN48H Timing + */ +#define RK043FN48H_HSYNC ((uint16_t)41) /* Horizontal synchronization */ +#define RK043FN48H_HBP ((uint16_t)13) /* Horizontal back porch */ +#define RK043FN48H_HFP ((uint16_t)32) /* Horizontal front porch */ +#define RK043FN48H_VSYNC ((uint16_t)10) /* Vertical synchronization */ +#define RK043FN48H_VBP ((uint16_t)2) /* Vertical back porch */ +#define RK043FN48H_VFP ((uint16_t)2) /* Vertical front porch */ + +/** + * @brief RK043FN48H frequency divider + */ +#define RK043FN48H_FREQUENCY_DIVIDER 5 /* LCD Frequency divider */ +/** + * @} + */ + +/** @defgroup RK043FN48H_Exported_Functions + * @{ + */ + +/** + * @} + */ +#ifdef __cplusplus +} +#endif + +#endif /* __RK043FN48H_H */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/s5k5cag/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/s5k5cag/Release_Notes.html new file mode 100644 index 00000000..c7dd932e --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/s5k5cag/Release_Notes.html @@ -0,0 +1,1096 @@ + + + + + + + + +Release Notes for S5K5CAG Component Driver + + + + + + + + + + + + +
+ +

 

+ +
+ + + + + +
+ + + + + + + +
+

Back to Release page

+
+

Release Notes for S5K5CAG Component Driver

+

Copyright + 2015 STMicroelectronics

+

+
+

 

+ + + + +
+

Update History

V1.0.1 +/ 05-June-2017

+ +

Main +Changes

+ + + + + + + + + + +
  • Update comments to be used for PDSC generation

V1.0.0 / 05-March-2015

+

Main Changes

+ +
    +
  • First official +release of S5K5CAG CAMERA component driver
  • +
+

License

+

Redistribution and use in source and + binary forms, with or without modification, are permitted provided that the + following conditions are met:

+
    +
  1. Redistributions + of source code must retain the above copyright notice, this list of + conditions and the following disclaimer.
  2. +
  3. Redistributions + in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution.
  4. +
  5. Neither + the name of STMicroelectronics nor the names of its contributors may + be used to endorse or promote products derived
  6. +
+

       from this software without specific prior written + permission.
+
+
THIS + SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE.

+

 

+
+
+
+

For + complete documentation on STM32 Microcontrollers + visit www.st.com/STM32

+
+

+
+ +
+ +

 

+ +
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/s5k5cag/s5k5cag.c b/src/port_stm32f7/common/bsp_drivers/Components/s5k5cag/s5k5cag.c new file mode 100644 index 00000000..806969a4 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/s5k5cag/s5k5cag.c @@ -0,0 +1,3448 @@ +/** + ****************************************************************************** + * @file s5k5cag.c + * @author MCD Application Team + * @brief This file provides the S5K5CAG camera driver + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "s5k5cag.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup S5K5CAG + * @brief This file provides a set of functions needed to drive the + * S5K5CAG Camera module. + * @{ + */ + +/** @defgroup S5K5CAG_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @defgroup S5K5CAG_Private_Defines + * @{ + */ + +/** + * @} + */ + +/** @defgroup S5K5CAG_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup S5K5CAG_Private_FunctionPrototypes + * @{ + */ +static uint32_t s5k5cag_ConvertValue(uint32_t feature, uint32_t value); +/** + * @} + */ + +/** @defgroup S5K5CAG_Private_Variables + * @{ + */ + +CAMERA_DrvTypeDef s5k5cag_drv = +{ + s5k5cag_Init, + s5k5cag_ReadID, + s5k5cag_Config, +}; + +/* Common initialization sequence for all resolutions */ +const uint16_t S5K5CAG_Common[][2]= +{ + /* ARM GO */ + /* Direct mode */ + {0xFCFC, 0xD000}, + {0x0010, 0x0001}, /* Reset */ + {0x1030, 0x0000}, /* Clear host interrupt so main will wait */ + {0x0014, 0x0001}, /* ARM go */ + {0xFFFF, 0x0064}, /* Min.10ms delay is required */ + + /* Set IO driving current */ + {0x0028, 0xD000}, + {0x002A, 0x1082}, + {0x0F12, 0x0155}, /* [9:8] D4, [7:6] D3, [5:4] D2, [3:2] D1, [1:0] D0 */ + {0x0F12, 0x0155}, /* [9:8] D9, [7:6] D8, [5:4] D7, [3:2] D6, [1:0] D5 */ + {0x0F12, 0x1555}, /* [5:4] GPIO3, [3:2] GPIO2, [1:0] GPIO1 */ + {0x0F12, 0x0555}, /* [11:10] SDA, [9:8] SCA, [7:6] PCLK, [3:2] VSYNC, [1:0] HSYNC */ + + /* Start T&P part */ + {0x0028, 0x7000}, + {0x002A, 0x2CF8}, + {0x0F12, 0xB510}, + {0x0F12, 0x490F}, + {0x0F12, 0x2000}, + {0x0F12, 0x8048}, + {0x0F12, 0x8088}, + {0x0F12, 0x490E}, + {0x0F12, 0x480E}, + {0x0F12, 0xF000}, + {0x0F12, 0xF949}, + {0x0F12, 0x490E}, + {0x0F12, 0x480E}, + {0x0F12, 0x6341}, + {0x0F12, 0x490E}, + {0x0F12, 0x38C0}, + {0x0F12, 0x63C1}, + {0x0F12, 0x490E}, + {0x0F12, 0x6301}, + {0x0F12, 0x490E}, + {0x0F12, 0x3040}, + {0x0F12, 0x6181}, + {0x0F12, 0x490D}, + {0x0F12, 0x480E}, + {0x0F12, 0xF000}, + {0x0F12, 0xF93A}, + {0x0F12, 0x490D}, + {0x0F12, 0x480E}, + {0x0F12, 0xF000}, + {0x0F12, 0xF936}, + {0x0F12, 0xBC10}, + {0x0F12, 0xBC08}, + {0x0F12, 0x4718}, + {0x0F12, 0x0000}, + {0x0F12, 0x1080}, + {0x0F12, 0xD000}, + {0x0F12, 0x2D69}, + {0x0F12, 0x7000}, + {0x0F12, 0x89A9}, + {0x0F12, 0x0000}, + {0x0F12, 0x2DBB}, + {0x0F12, 0x7000}, + {0x0F12, 0x0140}, + {0x0F12, 0x7000}, + {0x0F12, 0x2DED}, + {0x0F12, 0x7000}, + {0x0F12, 0x2E65}, + {0x0F12, 0x7000}, + {0x0F12, 0x2E79}, + {0x0F12, 0x7000}, + {0x0F12, 0x2E4D}, + {0x0F12, 0x7000}, + {0x0F12, 0x013D}, + {0x0F12, 0x0001}, + {0x0F12, 0x2F03}, + {0x0F12, 0x7000}, + {0x0F12, 0x5823}, + {0x0F12, 0x0000}, + {0x0F12, 0xB570}, + {0x0F12, 0x6804}, + {0x0F12, 0x6845}, + {0x0F12, 0x6881}, + {0x0F12, 0x6840}, + {0x0F12, 0x2900}, + {0x0F12, 0x6880}, + {0x0F12, 0xD007}, + {0x0F12, 0x4976}, + {0x0F12, 0x8949}, + {0x0F12, 0x084A}, + {0x0F12, 0x1880}, + {0x0F12, 0xF000}, + {0x0F12, 0xF914}, + {0x0F12, 0x80A0}, + {0x0F12, 0xE000}, + {0x0F12, 0x80A0}, + {0x0F12, 0x88A0}, + {0x0F12, 0x2800}, + {0x0F12, 0xD010}, + {0x0F12, 0x68A9}, + {0x0F12, 0x6828}, + {0x0F12, 0x084A}, + {0x0F12, 0x1880}, + {0x0F12, 0xF000}, + {0x0F12, 0xF908}, + {0x0F12, 0x8020}, + {0x0F12, 0x1D2D}, + {0x0F12, 0xCD03}, + {0x0F12, 0x084A}, + {0x0F12, 0x1880}, + {0x0F12, 0xF000}, + {0x0F12, 0xF901}, + {0x0F12, 0x8060}, + {0x0F12, 0xBC70}, + {0x0F12, 0xBC08}, + {0x0F12, 0x4718}, + {0x0F12, 0x2000}, + {0x0F12, 0x8060}, + {0x0F12, 0x8020}, + {0x0F12, 0xE7F8}, + {0x0F12, 0xB510}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8FC}, + {0x0F12, 0x4865}, + {0x0F12, 0x4966}, + {0x0F12, 0x8800}, + {0x0F12, 0x4A66}, + {0x0F12, 0x2805}, + {0x0F12, 0xD003}, + {0x0F12, 0x4B65}, + {0x0F12, 0x795B}, + {0x0F12, 0x2B00}, + {0x0F12, 0xD005}, + {0x0F12, 0x2001}, + {0x0F12, 0x8008}, + {0x0F12, 0x8010}, + {0x0F12, 0xBC10}, + {0x0F12, 0xBC08}, + {0x0F12, 0x4718}, + {0x0F12, 0x2800}, + {0x0F12, 0xD1FA}, + {0x0F12, 0x2000}, + {0x0F12, 0x8008}, + {0x0F12, 0x8010}, + {0x0F12, 0xE7F6}, + {0x0F12, 0xB570}, + {0x0F12, 0x0004}, + {0x0F12, 0x485D}, + {0x0F12, 0x2C00}, + {0x0F12, 0x8D00}, + {0x0F12, 0xD001}, + {0x0F12, 0x2501}, + {0x0F12, 0xE000}, + {0x0F12, 0x2500}, + {0x0F12, 0x4E5B}, + {0x0F12, 0x4328}, + {0x0F12, 0x8030}, + {0x0F12, 0x207D}, + {0x0F12, 0x00C0}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8DE}, + {0x0F12, 0x4858}, + {0x0F12, 0x2C00}, + {0x0F12, 0x8C40}, + {0x0F12, 0x0329}, + {0x0F12, 0x4308}, + {0x0F12, 0x8130}, + {0x0F12, 0x4856}, + {0x0F12, 0x2C00}, + {0x0F12, 0x8A40}, + {0x0F12, 0x01A9}, + {0x0F12, 0x4308}, + {0x0F12, 0x80B0}, + {0x0F12, 0x2C00}, + {0x0F12, 0xD00B}, + {0x0F12, 0x4853}, + {0x0F12, 0x8A01}, + {0x0F12, 0x4853}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8BD}, + {0x0F12, 0x4953}, + {0x0F12, 0x8809}, + {0x0F12, 0x4348}, + {0x0F12, 0x0400}, + {0x0F12, 0x0C00}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8C4}, + {0x0F12, 0x0020}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8C9}, + {0x0F12, 0x484F}, + {0x0F12, 0x7004}, + {0x0F12, 0xE7AF}, + {0x0F12, 0xB510}, + {0x0F12, 0x0004}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8CA}, + {0x0F12, 0x6020}, + {0x0F12, 0x494C}, + {0x0F12, 0x8B49}, + {0x0F12, 0x0789}, + {0x0F12, 0xD0BD}, + {0x0F12, 0x0040}, + {0x0F12, 0x6020}, + {0x0F12, 0xE7BA}, + {0x0F12, 0xB510}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8C7}, + {0x0F12, 0x4848}, + {0x0F12, 0x8880}, + {0x0F12, 0x0601}, + {0x0F12, 0x4840}, + {0x0F12, 0x1609}, + {0x0F12, 0x8281}, + {0x0F12, 0xE7B0}, + {0x0F12, 0xB5F8}, + {0x0F12, 0x000F}, + {0x0F12, 0x4C3A}, + {0x0F12, 0x3420}, + {0x0F12, 0x2500}, + {0x0F12, 0x5765}, + {0x0F12, 0x0039}, + {0x0F12, 0xF000}, + {0x0F12, 0xF8BF}, + {0x0F12, 0x9000}, + {0x0F12, 0x2600}, + {0x0F12, 0x57A6}, + {0x0F12, 0x4C38}, + {0x0F12, 0x42AE}, + {0x0F12, 0xD01B}, + {0x0F12, 0x4D3D}, + {0x0F12, 0x8AE8}, + {0x0F12, 0x2800}, + {0x0F12, 0xD013}, + {0x0F12, 0x4832}, + {0x0F12, 0x8A01}, + {0x0F12, 0x8B80}, + {0x0F12, 0x4378}, + {0x0F12, 0xF000}, + {0x0F12, 0xF881}, + {0x0F12, 0x89A9}, + {0x0F12, 0x1A41}, + {0x0F12, 0x4837}, + {0x0F12, 0x3820}, + {0x0F12, 0x8AC0}, + {0x0F12, 0x4348}, + {0x0F12, 0x17C1}, + {0x0F12, 0x0D89}, + {0x0F12, 0x1808}, + {0x0F12, 0x1280}, + {0x0F12, 0x8AA1}, + {0x0F12, 0x1A08}, + {0x0F12, 0x82A0}, + {0x0F12, 0xE003}, + {0x0F12, 0x88A8}, + {0x0F12, 0x0600}, + {0x0F12, 0x1600}, + {0x0F12, 0x82A0}, + {0x0F12, 0x2014}, + {0x0F12, 0x5E20}, + {0x0F12, 0x42B0}, + {0x0F12, 0xD011}, + {0x0F12, 0xF000}, + {0x0F12, 0xF89F}, + {0x0F12, 0x1D40}, + {0x0F12, 0x00C3}, + {0x0F12, 0x1A18}, + {0x0F12, 0x214B}, + {0x0F12, 0xF000}, + {0x0F12, 0xF863}, + {0x0F12, 0x211F}, + {0x0F12, 0xF000}, + {0x0F12, 0xF89E}, + {0x0F12, 0x2114}, + {0x0F12, 0x5E61}, + {0x0F12, 0x0FC9}, + {0x0F12, 0x0149}, + {0x0F12, 0x4301}, + {0x0F12, 0x4826}, + {0x0F12, 0x81C1}, + {0x0F12, 0x9800}, + {0x0F12, 0xBCF8}, + {0x0F12, 0xBC08}, + {0x0F12, 0x4718}, + {0x0F12, 0xB5F1}, + {0x0F12, 0xB082}, + {0x0F12, 0x2500}, + {0x0F12, 0x4822}, + {0x0F12, 0x9001}, + {0x0F12, 0x2400}, + {0x0F12, 0x2028}, + {0x0F12, 0x4368}, + {0x0F12, 0x4A21}, + {0x0F12, 0x4917}, + {0x0F12, 0x1882}, + {0x0F12, 0x39E0}, + {0x0F12, 0x1847}, + {0x0F12, 0x9200}, + {0x0F12, 0x0066}, + {0x0F12, 0x19B8}, + {0x0F12, 0x9A01}, + {0x0F12, 0x3060}, + {0x0F12, 0x8B01}, + {0x0F12, 0x5BB8}, + {0x0F12, 0x8812}, + {0x0F12, 0xF000}, + {0x0F12, 0xF884}, + {0x0F12, 0x9900}, + {0x0F12, 0x5388}, + {0x0F12, 0x1C64}, + {0x0F12, 0x2C14}, + {0x0F12, 0xDBF1}, + {0x0F12, 0x1C6D}, + {0x0F12, 0x2D03}, + {0x0F12, 0xDBE5}, + {0x0F12, 0x9802}, + {0x0F12, 0x6800}, + {0x0F12, 0x0600}, + {0x0F12, 0x0E00}, + {0x0F12, 0xF000}, + {0x0F12, 0xF87E}, + {0x0F12, 0xBCFE}, + {0x0F12, 0xBC08}, + {0x0F12, 0x4718}, + {0x0F12, 0x0000}, + {0x0F12, 0x0C3C}, + {0x0F12, 0x7000}, + {0x0F12, 0x26E8}, + {0x0F12, 0x7000}, + {0x0F12, 0x6100}, + {0x0F12, 0xD000}, + {0x0F12, 0x6500}, + {0x0F12, 0xD000}, + {0x0F12, 0x1A7C}, + {0x0F12, 0x7000}, + {0x0F12, 0x2C2C}, + {0x0F12, 0x7000}, + {0x0F12, 0xF400}, + {0x0F12, 0xD000}, + {0x0F12, 0x167C}, + {0x0F12, 0x7000}, + {0x0F12, 0x3368}, + {0x0F12, 0x7000}, + {0x0F12, 0x1D6C}, + {0x0F12, 0x7000}, + {0x0F12, 0x40A0}, + {0x0F12, 0x00DD}, + {0x0F12, 0xF520}, + {0x0F12, 0xD000}, + {0x0F12, 0x2C29}, + {0x0F12, 0x7000}, + {0x0F12, 0x1A54}, + {0x0F12, 0x7000}, + {0x0F12, 0x1564}, + {0x0F12, 0x7000}, + {0x0F12, 0xF2A0}, + {0x0F12, 0xD000}, + {0x0F12, 0x2440}, + {0x0F12, 0x7000}, + {0x0F12, 0x05A0}, + {0x0F12, 0x7000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x1A3F}, + {0x0F12, 0x0001}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xF004}, + {0x0F12, 0xE51F}, + {0x0F12, 0x1F48}, + {0x0F12, 0x0001}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x24BD}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0xF53F}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0xF5D9}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x013D}, + {0x0F12, 0x0001}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0xF5C9}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0xFAA9}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x36DD}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x36ED}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x3723}, + {0x0F12, 0x0000}, + {0x0F12, 0x4778}, + {0x0F12, 0x46C0}, + {0x0F12, 0xC000}, + {0x0F12, 0xE59F}, + {0x0F12, 0xFF1C}, + {0x0F12, 0xE12F}, + {0x0F12, 0x5823}, + {0x0F12, 0x0000}, + {0x0F12, 0x7D3E}, + {0x0F12, 0x0000}, + /* End T&P part */ + + /* CIS/APS/Analog setting- 400LSBSYSCLK 45M */ + {0x0028, 0x7000}, + {0x002A, 0x157A}, + {0x0F12, 0x0001}, + {0x002A, 0x1578}, + {0x0F12, 0x0001}, + {0x002A, 0x1576}, + {0x0F12, 0x0020}, + {0x002A, 0x1574}, + {0x0F12, 0x0006}, + {0x002A, 0x156E}, + {0x0F12, 0x0001}, /* Slope calibration tolerance in units of 1/256 */ + {0x002A, 0x1568}, + {0x0F12, 0x00FC}, + + /* ADC control */ + {0x002A, 0x155A}, + {0x0F12, 0x01CC}, /* ADC SAT of 450mV for 10bit default in EVT1 */ + {0x002A, 0x157E}, + {0x0F12, 0x0C80}, /* 3200 Max. Reset ramp DCLK counts (default 2048 0x800) */ + {0x0F12, 0x0578}, /* 1400 Max. Reset ramp DCLK counts for x3.5 */ + {0x002A, 0x157C}, + {0x0F12, 0x0190}, /* 400 Reset ramp for x1 in DCLK counts */ + {0x002A, 0x1570}, + {0x0F12, 0x00A0}, /* 224 LSB */ + {0x0F12, 0x0010}, /* reset threshold */ + {0x002A, 0x12C4}, + {0x0F12, 0x006A}, /* 106 additional timing columns */ + {0x002A, 0x12C8}, + {0x0F12, 0x08AC}, /* 2220 ADC columns in normal mode including Hold & Latch */ + {0x0F12, 0x0050}, /* 80 addition of ADC columns in Y-ave mode (default 244 0x74) */ + + {0x002A, 0x1696}, + {0x0F12, 0x0000}, /* based on APS guidelines */ + {0x0F12, 0x0000}, /* based on APS guidelines */ + {0x0F12, 0x00C6}, /* default. 1492 used for ADC dark characteristics */ + {0x0F12, 0x00C6}, /* default. 1492 used for ADC dark characteristics */ + {0x002A, 0x1690}, + {0x0F12, 0x0001}, /* when set double sampling is activated - requires different set of pointers */ + {0x002A, 0x12B0}, + {0x0F12, 0x0055}, /* comp and pixel bias control 0xF40E - default for EVT1 */ + {0x0F12, 0x005A}, /* comp and pixel bias control 0xF40E for binning mode */ + {0x002A, 0x337A}, + {0x0F12, 0x0006}, /* [7] - is used for rest-only mode (EVT0 value is 0xD and HW 0x6) */ + {0x002A, 0x169E}, /* [3:0]- specifies the target (default 7)- DCLK = 64MHz instead of 116MHz */ + {0x0F12, 0x000A}, + {0x0028, 0xD000}, + {0x002A, 0xF406}, + {0x0F12, 0x1000}, /* [11]: Enable DBLR Regulation */ + {0x002A, 0xF40A}, + {0x0F12, 0x6998}, /* [3:0]: VPIX ~2.8V */ + {0x002A, 0xF418}, + {0x0F12, 0x0078}, /* [0]: Static RC-filter */ + {0x0F12, 0x04FE}, /* [7:4]: Full RC-filter */ + {0x002A, 0xF52C}, + {0x0F12, 0x8800}, /* [11]: Add load to CDS block */ + + {0x002A, 0x3274}, + {0x0F12, 0x0155}, + {0x0F12, 0x0155}, + {0x0F12, 0x1555}, + {0x0F12, 0x0555}, + + /* Asserting CDS pointers - Long exposure MS Normal */ + /* Conditions: 10bit, ADC_SAT = 450mV ; ramp_del = 22 ; ramp_start = 34 */ + {0x0028, 0x7000}, + {0x002A, 0x12D2}, + {0x0F12, 0x0003}, /* #senHal_pContSenModesRegsArray[0][0]2 700012D2 */ + {0x0F12, 0x0003}, /* #senHal_pContSenModesRegsArray[0][1]2 700012D4 */ + {0x0F12, 0x0003}, /* #senHal_pContSenModesRegsArray[0][2]2 700012D6 */ + {0x0F12, 0x0003}, /* #senHal_pContSenModesRegsArray[0][3]2 700012D8 */ + {0x0F12, 0x0884}, /* #senHal_pContSenModesRegsArray[1][0]2 700012DA */ + {0x0F12, 0x08CF}, /* #senHal_pContSenModesRegsArray[1][1]2 700012DC */ + {0x0F12, 0x0500}, /* #senHal_pContSenModesRegsArray[1][2]2 700012DE */ + {0x0F12, 0x054B}, /* #senHal_pContSenModesRegsArray[1][3]2 700012E0 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[2][0]2 700012E2 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[2][1]2 700012E4 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[2][2]2 700012E6 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[2][3]2 700012E8 */ + {0x0F12, 0x0885}, /* #senHal_pContSenModesRegsArray[3][0]2 700012EA */ + {0x0F12, 0x0467}, /* #senHal_pContSenModesRegsArray[3][1]2 700012EC */ + {0x0F12, 0x0501}, /* #senHal_pContSenModesRegsArray[3][2]2 700012EE */ + {0x0F12, 0x02A5}, /* #senHal_pContSenModesRegsArray[3][3]2 700012F0 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[4][0]2 700012F2 */ + {0x0F12, 0x046A}, /* #senHal_pContSenModesRegsArray[4][1]2 700012F4 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[4][2]2 700012F6 */ + {0x0F12, 0x02A8}, /* #senHal_pContSenModesRegsArray[4][3]2 700012F8 */ + {0x0F12, 0x0885}, /* #senHal_pContSenModesRegsArray[5][0]2 700012FA */ + {0x0F12, 0x08D0}, /* #senHal_pContSenModesRegsArray[5][1]2 700012FC */ + {0x0F12, 0x0501}, /* #senHal_pContSenModesRegsArray[5][2]2 700012FE */ + {0x0F12, 0x054C}, /* #senHal_pContSenModesRegsArray[5][3]2 70001300 */ + {0x0F12, 0x0006}, /* #senHal_pContSenModesRegsArray[6][0]2 70001302 */ + {0x0F12, 0x0020}, /* #senHal_pContSenModesRegsArray[6][1]2 70001304 */ + {0x0F12, 0x0006}, /* #senHal_pContSenModesRegsArray[6][2]2 70001306 */ + {0x0F12, 0x0020}, /* #senHal_pContSenModesRegsArray[6][3]2 70001308 */ + {0x0F12, 0x0881}, /* #senHal_pContSenModesRegsArray[7][0]2 7000130A */ + {0x0F12, 0x0463}, /* #senHal_pContSenModesRegsArray[7][1]2 7000130C */ + {0x0F12, 0x04FD}, /* #senHal_pContSenModesRegsArray[7][2]2 7000130E */ + {0x0F12, 0x02A1}, /* #senHal_pContSenModesRegsArray[7][3]2 70001310 */ + {0x0F12, 0x0006}, /* #senHal_pContSenModesRegsArray[8][0]2 70001312 */ + {0x0F12, 0x0489}, /* #senHal_pContSenModesRegsArray[8][1]2 70001314 */ + {0x0F12, 0x0006}, /* #senHal_pContSenModesRegsArray[8][2]2 70001316 */ + {0x0F12, 0x02C7}, /* #senHal_pContSenModesRegsArray[8][3]2 70001318 */ + {0x0F12, 0x0881}, /* #senHal_pContSenModesRegsArray[9][0]2 7000131A */ + {0x0F12, 0x08CC}, /* #senHal_pContSenModesRegsArray[9][1]2 7000131C */ + {0x0F12, 0x04FD}, /* #senHal_pContSenModesRegsArray[9][2]2 7000131E */ + {0x0F12, 0x0548}, /* #senHal_pContSenModesRegsArray[9][3]2 70001320 */ + {0x0F12, 0x03A2}, /* #senHal_pContSenModesRegsArray[10][0] 2 70001322 */ + {0x0F12, 0x01D3}, /* #senHal_pContSenModesRegsArray[10][1] 2 70001324 */ + {0x0F12, 0x01E0}, /* #senHal_pContSenModesRegsArray[10][2] 2 70001326 */ + {0x0F12, 0x00F2}, /* #senHal_pContSenModesRegsArray[10][3] 2 70001328 */ + {0x0F12, 0x03F2}, /* #senHal_pContSenModesRegsArray[11][0] 2 7000132A */ + {0x0F12, 0x0223}, /* #senHal_pContSenModesRegsArray[11][1] 2 7000132C */ + {0x0F12, 0x0230}, /* #senHal_pContSenModesRegsArray[11][2] 2 7000132E */ + {0x0F12, 0x0142}, /* #senHal_pContSenModesRegsArray[11][3] 2 70001330 */ + {0x0F12, 0x03A2}, /* #senHal_pContSenModesRegsArray[12][0] 2 70001332 */ + {0x0F12, 0x063C}, /* #senHal_pContSenModesRegsArray[12][1] 2 70001334 */ + {0x0F12, 0x01E0}, /* #senHal_pContSenModesRegsArray[12][2] 2 70001336 */ + {0x0F12, 0x0399}, /* #senHal_pContSenModesRegsArray[12][3] 2 70001338 */ + {0x0F12, 0x03F2}, /* #senHal_pContSenModesRegsArray[13][0] 2 7000133A */ + {0x0F12, 0x068C}, /* #senHal_pContSenModesRegsArray[13][1] 2 7000133C */ + {0x0F12, 0x0230}, /* #senHal_pContSenModesRegsArray[13][2] 2 7000133E */ + {0x0F12, 0x03E9}, /* #senHal_pContSenModesRegsArray[13][3] 2 70001340 */ + {0x0F12, 0x0002}, /* #senHal_pContSenModesRegsArray[14][0] 2 70001342 */ + {0x0F12, 0x0002}, /* #senHal_pContSenModesRegsArray[14][1] 2 70001344 */ + {0x0F12, 0x0002}, /* #senHal_pContSenModesRegsArray[14][2] 2 70001346 */ + {0x0F12, 0x0002}, /* #senHal_pContSenModesRegsArray[14][3] 2 70001348 */ + {0x0F12, 0x003C}, /* #senHal_pContSenModesRegsArray[15][0] 2 7000134A */ + {0x0F12, 0x003C}, /* #senHal_pContSenModesRegsArray[15][1] 2 7000134C */ + {0x0F12, 0x003C}, /* #senHal_pContSenModesRegsArray[15][2] 2 7000134E */ + {0x0F12, 0x003C}, /* #senHal_pContSenModesRegsArray[15][3] 2 70001350 */ + {0x0F12, 0x01D3}, /* #senHal_pContSenModesRegsArray[16][0] 2 70001352 */ + {0x0F12, 0x01D3}, /* #senHal_pContSenModesRegsArray[16][1] 2 70001354 */ + {0x0F12, 0x00F2}, /* #senHal_pContSenModesRegsArray[16][2] 2 70001356 */ + {0x0F12, 0x00F2}, /* #senHal_pContSenModesRegsArray[16][3] 2 70001358 */ + {0x0F12, 0x020B}, /* #senHal_pContSenModesRegsArray[17][0] 2 7000135A */ + {0x0F12, 0x024A}, /* #senHal_pContSenModesRegsArray[17][1] 2 7000135C */ + {0x0F12, 0x012A}, /* #senHal_pContSenModesRegsArray[17][2] 2 7000135E */ + {0x0F12, 0x0169}, /* #senHal_pContSenModesRegsArray[17][3] 2 70001360 */ + {0x0F12, 0x0002}, /* #senHal_pContSenModesRegsArray[18][0] 2 70001362 */ + {0x0F12, 0x046B}, /* #senHal_pContSenModesRegsArray[18][1] 2 70001364 */ + {0x0F12, 0x0002}, /* #senHal_pContSenModesRegsArray[18][2] 2 70001366 */ + {0x0F12, 0x02A9}, /* #senHal_pContSenModesRegsArray[18][3] 2 70001368 */ + {0x0F12, 0x0419}, /* #senHal_pContSenModesRegsArray[19][0] 2 7000136A */ + {0x0F12, 0x04A5}, /* #senHal_pContSenModesRegsArray[19][1] 2 7000136C */ + {0x0F12, 0x0257}, /* #senHal_pContSenModesRegsArray[19][2] 2 7000136E */ + {0x0F12, 0x02E3}, /* #senHal_pContSenModesRegsArray[19][3] 2 70001370 */ + {0x0F12, 0x0630}, /* #senHal_pContSenModesRegsArray[20][0] 2 70001372 */ + {0x0F12, 0x063C}, /* #senHal_pContSenModesRegsArray[20][1] 2 70001374 */ + {0x0F12, 0x038D}, /* #senHal_pContSenModesRegsArray[20][2] 2 70001376 */ + {0x0F12, 0x0399}, /* #senHal_pContSenModesRegsArray[20][3] 2 70001378 */ + {0x0F12, 0x0668}, /* #senHal_pContSenModesRegsArray[21][0] 2 7000137A */ + {0x0F12, 0x06B3}, /* #senHal_pContSenModesRegsArray[21][1] 2 7000137C */ + {0x0F12, 0x03C5}, /* #senHal_pContSenModesRegsArray[21][2] 2 7000137E */ + {0x0F12, 0x0410}, /* #senHal_pContSenModesRegsArray[21][3] 2 70001380 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[22][0] 2 70001382 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[22][1] 2 70001384 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[22][2] 2 70001386 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[22][3] 2 70001388 */ + {0x0F12, 0x03A2}, /* #senHal_pContSenModesRegsArray[23][0] 2 7000138A */ + {0x0F12, 0x01D3}, /* #senHal_pContSenModesRegsArray[23][1] 2 7000138C */ + {0x0F12, 0x01E0}, /* #senHal_pContSenModesRegsArray[23][2] 2 7000138E */ + {0x0F12, 0x00F2}, /* #senHal_pContSenModesRegsArray[23][3] 2 70001390 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[24][0] 2 70001392 */ + {0x0F12, 0x0461}, /* #senHal_pContSenModesRegsArray[24][1] 2 70001394 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[24][2] 2 70001396 */ + {0x0F12, 0x029F}, /* #senHal_pContSenModesRegsArray[24][3] 2 70001398 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[25][0] 2 7000139A */ + {0x0F12, 0x063C}, /* #senHal_pContSenModesRegsArray[25][1] 2 7000139C */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[25][2] 2 7000139E */ + {0x0F12, 0x0399}, /* #senHal_pContSenModesRegsArray[25][3] 2 700013A0 */ + {0x0F12, 0x003D}, /* #senHal_pContSenModesRegsArray[26][0] 2 700013A2 */ + {0x0F12, 0x003D}, /* #senHal_pContSenModesRegsArray[26][1] 2 700013A4 */ + {0x0F12, 0x003D}, /* #senHal_pContSenModesRegsArray[26][2] 2 700013A6 */ + {0x0F12, 0x003D}, /* #senHal_pContSenModesRegsArray[26][3] 2 700013A8 */ + {0x0F12, 0x01D0}, /* #senHal_pContSenModesRegsArray[27][0] 2 700013AA */ + {0x0F12, 0x01D0}, /* #senHal_pContSenModesRegsArray[27][1] 2 700013AC */ + {0x0F12, 0x00EF}, /* #senHal_pContSenModesRegsArray[27][2] 2 700013AE */ + {0x0F12, 0x00EF}, /* #senHal_pContSenModesRegsArray[27][3] 2 700013B0 */ + {0x0F12, 0x020C}, /* #senHal_pContSenModesRegsArray[28][0] 2 700013B2 */ + {0x0F12, 0x024B}, /* #senHal_pContSenModesRegsArray[28][1] 2 700013B4 */ + {0x0F12, 0x012B}, /* #senHal_pContSenModesRegsArray[28][2] 2 700013B6 */ + {0x0F12, 0x016A}, /* #senHal_pContSenModesRegsArray[28][3] 2 700013B8 */ + {0x0F12, 0x039F}, /* #senHal_pContSenModesRegsArray[29][0] 2 700013BA */ + {0x0F12, 0x045E}, /* #senHal_pContSenModesRegsArray[29][1] 2 700013BC */ + {0x0F12, 0x01DD}, /* #senHal_pContSenModesRegsArray[29][2] 2 700013BE */ + {0x0F12, 0x029C}, /* #senHal_pContSenModesRegsArray[29][3] 2 700013C0 */ + {0x0F12, 0x041A}, /* #senHal_pContSenModesRegsArray[30][0] 2 700013C2 */ + {0x0F12, 0x04A6}, /* #senHal_pContSenModesRegsArray[30][1] 2 700013C4 */ + {0x0F12, 0x0258}, /* #senHal_pContSenModesRegsArray[30][2] 2 700013C6 */ + {0x0F12, 0x02E4}, /* #senHal_pContSenModesRegsArray[30][3] 2 700013C8 */ + {0x0F12, 0x062D}, /* #senHal_pContSenModesRegsArray[31][0] 2 700013CA */ + {0x0F12, 0x0639}, /* #senHal_pContSenModesRegsArray[31][1] 2 700013CC */ + {0x0F12, 0x038A}, /* #senHal_pContSenModesRegsArray[31][2] 2 700013CE */ + {0x0F12, 0x0396}, /* #senHal_pContSenModesRegsArray[31][3] 2 700013D0 */ + {0x0F12, 0x0669}, /* #senHal_pContSenModesRegsArray[32][0] 2 700013D2 */ + {0x0F12, 0x06B4}, /* #senHal_pContSenModesRegsArray[32][1] 2 700013D4 */ + {0x0F12, 0x03C6}, /* #senHal_pContSenModesRegsArray[32][2] 2 700013D6 */ + {0x0F12, 0x0411}, /* #senHal_pContSenModesRegsArray[32][3] 2 700013D8 */ + {0x0F12, 0x087C}, /* #senHal_pContSenModesRegsArray[33][0] 2 700013DA */ + {0x0F12, 0x08C7}, /* #senHal_pContSenModesRegsArray[33][1] 2 700013DC */ + {0x0F12, 0x04F8}, /* #senHal_pContSenModesRegsArray[33][2] 2 700013DE */ + {0x0F12, 0x0543}, /* #senHal_pContSenModesRegsArray[33][3] 2 700013E0 */ + {0x0F12, 0x0040}, /* #senHal_pContSenModesRegsArray[34][0] 2 700013E2 */ + {0x0F12, 0x0040}, /* #senHal_pContSenModesRegsArray[34][1] 2 700013E4 */ + {0x0F12, 0x0040}, /* #senHal_pContSenModesRegsArray[34][2] 2 700013E6 */ + {0x0F12, 0x0040}, /* #senHal_pContSenModesRegsArray[34][3] 2 700013E8 */ + {0x0F12, 0x01D0}, /* #senHal_pContSenModesRegsArray[35][0] 2 700013EA */ + {0x0F12, 0x01D0}, /* #senHal_pContSenModesRegsArray[35][1] 2 700013EC */ + {0x0F12, 0x00EF}, /* #senHal_pContSenModesRegsArray[35][2] 2 700013EE */ + {0x0F12, 0x00EF}, /* #senHal_pContSenModesRegsArray[35][3] 2 700013F0 */ + {0x0F12, 0x020F}, /* #senHal_pContSenModesRegsArray[36][0] 2 700013F2 */ + {0x0F12, 0x024E}, /* #senHal_pContSenModesRegsArray[36][1] 2 700013F4 */ + {0x0F12, 0x012E}, /* #senHal_pContSenModesRegsArray[36][2] 2 700013F6 */ + {0x0F12, 0x016D}, /* #senHal_pContSenModesRegsArray[36][3] 2 700013F8 */ + {0x0F12, 0x039F}, /* #senHal_pContSenModesRegsArray[37][0] 2 700013FA */ + {0x0F12, 0x045E}, /* #senHal_pContSenModesRegsArray[37][1] 2 700013FC */ + {0x0F12, 0x01DD}, /* #senHal_pContSenModesRegsArray[37][2] 2 700013FE */ + {0x0F12, 0x029C}, /* #senHal_pContSenModesRegsArray[37][3] 2 70001400 */ + {0x0F12, 0x041D}, /* #senHal_pContSenModesRegsArray[38][0] 2 70001402 */ + {0x0F12, 0x04A9}, /* #senHal_pContSenModesRegsArray[38][1] 2 70001404 */ + {0x0F12, 0x025B}, /* #senHal_pContSenModesRegsArray[38][2] 2 70001406 */ + {0x0F12, 0x02E7}, /* #senHal_pContSenModesRegsArray[38][3] 2 70001408 */ + {0x0F12, 0x062D}, /* #senHal_pContSenModesRegsArray[39][0] 2 7000140A */ + {0x0F12, 0x0639}, /* #senHal_pContSenModesRegsArray[39][1] 2 7000140C */ + {0x0F12, 0x038A}, /* #senHal_pContSenModesRegsArray[39][2] 2 7000140E */ + {0x0F12, 0x0396}, /* #senHal_pContSenModesRegsArray[39][3] 2 70001410 */ + {0x0F12, 0x066C}, /* #senHal_pContSenModesRegsArray[40][0] 2 70001412 */ + {0x0F12, 0x06B7}, /* #senHal_pContSenModesRegsArray[40][1] 2 70001414 */ + {0x0F12, 0x03C9}, /* #senHal_pContSenModesRegsArray[40][2] 2 70001416 */ + {0x0F12, 0x0414}, /* #senHal_pContSenModesRegsArray[40][3] 2 70001418 */ + {0x0F12, 0x087C}, /* #senHal_pContSenModesRegsArray[41][0] 2 7000141A */ + {0x0F12, 0x08C7}, /* #senHal_pContSenModesRegsArray[41][1] 2 7000141C */ + {0x0F12, 0x04F8}, /* #senHal_pContSenModesRegsArray[41][2] 2 7000141E */ + {0x0F12, 0x0543}, /* #senHal_pContSenModesRegsArray[41][3] 2 70001420 */ + {0x0F12, 0x0040}, /* #senHal_pContSenModesRegsArray[42][0] 2 70001422 */ + {0x0F12, 0x0040}, /* #senHal_pContSenModesRegsArray[42][1] 2 70001424 */ + {0x0F12, 0x0040}, /* #senHal_pContSenModesRegsArray[42][2] 2 70001426 */ + {0x0F12, 0x0040}, /* #senHal_pContSenModesRegsArray[42][3] 2 70001428 */ + {0x0F12, 0x01D0}, /* #senHal_pContSenModesRegsArray[43][0] 2 7000142A */ + {0x0F12, 0x01D0}, /* #senHal_pContSenModesRegsArray[43][1] 2 7000142C */ + {0x0F12, 0x00EF}, /* #senHal_pContSenModesRegsArray[43][2] 2 7000142E */ + {0x0F12, 0x00EF}, /* #senHal_pContSenModesRegsArray[43][3] 2 70001430 */ + {0x0F12, 0x020F}, /* #senHal_pContSenModesRegsArray[44][0] 2 70001432 */ + {0x0F12, 0x024E}, /* #senHal_pContSenModesRegsArray[44][1] 2 70001434 */ + {0x0F12, 0x012E}, /* #senHal_pContSenModesRegsArray[44][2] 2 70001436 */ + {0x0F12, 0x016D}, /* #senHal_pContSenModesRegsArray[44][3] 2 70001438 */ + {0x0F12, 0x039F}, /* #senHal_pContSenModesRegsArray[45][0] 2 7000143A */ + {0x0F12, 0x045E}, /* #senHal_pContSenModesRegsArray[45][1] 2 7000143C */ + {0x0F12, 0x01DD}, /* #senHal_pContSenModesRegsArray[45][2] 2 7000143E */ + {0x0F12, 0x029C}, /* #senHal_pContSenModesRegsArray[45][3] 2 70001440 */ + {0x0F12, 0x041D}, /* #senHal_pContSenModesRegsArray[46][0] 2 70001442 */ + {0x0F12, 0x04A9}, /* #senHal_pContSenModesRegsArray[46][1] 2 70001444 */ + {0x0F12, 0x025B}, /* #senHal_pContSenModesRegsArray[46][2] 2 70001446 */ + {0x0F12, 0x02E7}, /* #senHal_pContSenModesRegsArray[46][3] 2 70001448 */ + {0x0F12, 0x062D}, /* #senHal_pContSenModesRegsArray[47][0] 2 7000144A */ + {0x0F12, 0x0639}, /* #senHal_pContSenModesRegsArray[47][1] 2 7000144C */ + {0x0F12, 0x038A}, /* #senHal_pContSenModesRegsArray[47][2] 2 7000144E */ + {0x0F12, 0x0396}, /* #senHal_pContSenModesRegsArray[47][3] 2 70001450 */ + {0x0F12, 0x066C}, /* #senHal_pContSenModesRegsArray[48][0] 2 70001452 */ + {0x0F12, 0x06B7}, /* #senHal_pContSenModesRegsArray[48][1] 2 70001454 */ + {0x0F12, 0x03C9}, /* #senHal_pContSenModesRegsArray[48][2] 2 70001456 */ + {0x0F12, 0x0414}, /* #senHal_pContSenModesRegsArray[48][3] 2 70001458 */ + {0x0F12, 0x087C}, /* #senHal_pContSenModesRegsArray[49][0] 2 7000145A */ + {0x0F12, 0x08C7}, /* #senHal_pContSenModesRegsArray[49][1] 2 7000145C */ + {0x0F12, 0x04F8}, /* #senHal_pContSenModesRegsArray[49][2] 2 7000145E */ + {0x0F12, 0x0543}, /* #senHal_pContSenModesRegsArray[49][3] 2 70001460 */ + {0x0F12, 0x003D}, /* #senHal_pContSenModesRegsArray[50][0] 2 70001462 */ + {0x0F12, 0x003D}, /* #senHal_pContSenModesRegsArray[50][1] 2 70001464 */ + {0x0F12, 0x003D}, /* #senHal_pContSenModesRegsArray[50][2] 2 70001466 */ + {0x0F12, 0x003D}, /* #senHal_pContSenModesRegsArray[50][3] 2 70001468 */ + {0x0F12, 0x01D2}, /* #senHal_pContSenModesRegsArray[51][0] 2 7000146A */ + {0x0F12, 0x01D2}, /* #senHal_pContSenModesRegsArray[51][1] 2 7000146C */ + {0x0F12, 0x00F1}, /* #senHal_pContSenModesRegsArray[51][2] 2 7000146E */ + {0x0F12, 0x00F1}, /* #senHal_pContSenModesRegsArray[51][3] 2 70001470 */ + {0x0F12, 0x020C}, /* #senHal_pContSenModesRegsArray[52][0] 2 70001472 */ + {0x0F12, 0x024B}, /* #senHal_pContSenModesRegsArray[52][1] 2 70001474 */ + {0x0F12, 0x012B}, /* #senHal_pContSenModesRegsArray[52][2] 2 70001476 */ + {0x0F12, 0x016A}, /* #senHal_pContSenModesRegsArray[52][3] 2 70001478 */ + {0x0F12, 0x03A1}, /* #senHal_pContSenModesRegsArray[53][0] 2 7000147A */ + {0x0F12, 0x0460}, /* #senHal_pContSenModesRegsArray[53][1] 2 7000147C */ + {0x0F12, 0x01DF}, /* #senHal_pContSenModesRegsArray[53][2] 2 7000147E */ + {0x0F12, 0x029E}, /* #senHal_pContSenModesRegsArray[53][3] 2 70001480 */ + {0x0F12, 0x041A}, /* #senHal_pContSenModesRegsArray[54][0] 2 70001482 */ + {0x0F12, 0x04A6}, /* #senHal_pContSenModesRegsArray[54][1] 2 70001484 */ + {0x0F12, 0x0258}, /* #senHal_pContSenModesRegsArray[54][2] 2 70001486 */ + {0x0F12, 0x02E4}, /* #senHal_pContSenModesRegsArray[54][3] 2 70001488 */ + {0x0F12, 0x062F}, /* #senHal_pContSenModesRegsArray[55][0] 2 7000148A */ + {0x0F12, 0x063B}, /* #senHal_pContSenModesRegsArray[55][1] 2 7000148C */ + {0x0F12, 0x038C}, /* #senHal_pContSenModesRegsArray[55][2] 2 7000148E */ + {0x0F12, 0x0398}, /* #senHal_pContSenModesRegsArray[55][3] 2 70001490 */ + {0x0F12, 0x0669}, /* #senHal_pContSenModesRegsArray[56][0] 2 70001492 */ + {0x0F12, 0x06B4}, /* #senHal_pContSenModesRegsArray[56][1] 2 70001494 */ + {0x0F12, 0x03C6}, /* #senHal_pContSenModesRegsArray[56][2] 2 70001496 */ + {0x0F12, 0x0411}, /* #senHal_pContSenModesRegsArray[56][3] 2 70001498 */ + {0x0F12, 0x087E}, /* #senHal_pContSenModesRegsArray[57][0] 2 7000149A */ + {0x0F12, 0x08C9}, /* #senHal_pContSenModesRegsArray[57][1] 2 7000149C */ + {0x0F12, 0x04FA}, /* #senHal_pContSenModesRegsArray[57][2] 2 7000149E */ + {0x0F12, 0x0545}, /* #senHal_pContSenModesRegsArray[57][3] 2 700014A0 */ + {0x0F12, 0x03A2}, /* #senHal_pContSenModesRegsArray[58][0] 2 700014A2 */ + {0x0F12, 0x01D3}, /* #senHal_pContSenModesRegsArray[58][1] 2 700014A4 */ + {0x0F12, 0x01E0}, /* #senHal_pContSenModesRegsArray[58][2] 2 700014A6 */ + {0x0F12, 0x00F2}, /* #senHal_pContSenModesRegsArray[58][3] 2 700014A8 */ + {0x0F12, 0x03AF}, /* #senHal_pContSenModesRegsArray[59][0] 2 700014AA */ + {0x0F12, 0x01E0}, /* #senHal_pContSenModesRegsArray[59][1] 2 700014AC */ + {0x0F12, 0x01ED}, /* #senHal_pContSenModesRegsArray[59][2] 2 700014AE */ + {0x0F12, 0x00FF}, /* #senHal_pContSenModesRegsArray[59][3] 2 700014B0 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[60][0] 2 700014B2 */ + {0x0F12, 0x0461}, /* #senHal_pContSenModesRegsArray[60][1] 2 700014B4 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[60][2] 2 700014B6 */ + {0x0F12, 0x029F}, /* #senHal_pContSenModesRegsArray[60][3] 2 700014B8 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[61][0] 2 700014BA */ + {0x0F12, 0x046E}, /* #senHal_pContSenModesRegsArray[61][1] 2 700014BC */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[61][2] 2 700014BE */ + {0x0F12, 0x02AC}, /* #senHal_pContSenModesRegsArray[61][3] 2 700014C0 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[62][0] 2 700014C2 */ + {0x0F12, 0x063C}, /* #senHal_pContSenModesRegsArray[62][1] 2 700014C4 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[62][2] 2 700014C6 */ + {0x0F12, 0x0399}, /* #senHal_pContSenModesRegsArray[62][3] 2 700014C8 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[63][0] 2 700014CA */ + {0x0F12, 0x0649}, /* #senHal_pContSenModesRegsArray[63][1] 2 700014CC */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[63][2] 2 700014CE */ + {0x0F12, 0x03A6}, /* #senHal_pContSenModesRegsArray[63][3] 2 700014D0 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[64][0] 2 700014D2 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[64][1] 2 700014D4 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[64][2] 2 700014D6 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[64][3] 2 700014D8 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[65][0] 2 700014DA */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[65][1] 2 700014DC */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[65][2] 2 700014DE */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[65][3] 2 700014E0 */ + {0x0F12, 0x03AA}, /* #senHal_pContSenModesRegsArray[66][0] 2 700014E2 */ + {0x0F12, 0x01DB}, /* #senHal_pContSenModesRegsArray[66][1] 2 700014E4 */ + {0x0F12, 0x01E8}, /* #senHal_pContSenModesRegsArray[66][2] 2 700014E6 */ + {0x0F12, 0x00FA}, /* #senHal_pContSenModesRegsArray[66][3] 2 700014E8 */ + {0x0F12, 0x03B7}, /* #senHal_pContSenModesRegsArray[67][0] 2 700014EA */ + {0x0F12, 0x01E8}, /* #senHal_pContSenModesRegsArray[67][1] 2 700014EC */ + {0x0F12, 0x01F5}, /* #senHal_pContSenModesRegsArray[67][2] 2 700014EE */ + {0x0F12, 0x0107}, /* #senHal_pContSenModesRegsArray[67][3] 2 700014F0 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[68][0] 2 700014F2 */ + {0x0F12, 0x0469}, /* #senHal_pContSenModesRegsArray[68][1] 2 700014F4 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[68][2] 2 700014F6 */ + {0x0F12, 0x02A7}, /* #senHal_pContSenModesRegsArray[68][3] 2 700014F8 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[69][0] 2 700014FA */ + {0x0F12, 0x0476}, /* #senHal_pContSenModesRegsArray[69][1] 2 700014FC */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[69][2] 2 700014FE */ + {0x0F12, 0x02B4}, /* #senHal_pContSenModesRegsArray[69][3] 2 70001500 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[70][0] 2 70001502 */ + {0x0F12, 0x0644}, /* #senHal_pContSenModesRegsArray[70][1] 2 70001504 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[70][2] 2 70001506 */ + {0x0F12, 0x03A1}, /* #senHal_pContSenModesRegsArray[70][3] 2 70001508 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[71][0] 2 7000150A */ + {0x0F12, 0x0651}, /* #senHal_pContSenModesRegsArray[71][1] 2 7000150C */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[71][2] 2 7000150E */ + {0x0F12, 0x03AE}, /* #senHal_pContSenModesRegsArray[71][3] 2 70001510 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[72][0] 2 70001512 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[72][1] 2 70001514 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[72][2] 2 70001516 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[72][3] 2 70001518 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[73][0] 2 7000151A */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[73][1] 2 7000151C */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[73][2] 2 7000151E */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[73][3] 2 70001520 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[74][0] 2 70001522 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[74][1] 2 70001524 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[74][2] 2 70001526 */ + {0x0F12, 0x0001}, /* #senHal_pContSenModesRegsArray[74][3] 2 70001528 */ + {0x0F12, 0x000F}, /* #senHal_pContSenModesRegsArray[75][0] 2 7000152A */ + {0x0F12, 0x000F}, /* #senHal_pContSenModesRegsArray[75][1] 2 7000152C */ + {0x0F12, 0x000F}, /* #senHal_pContSenModesRegsArray[75][2] 2 7000152E */ + {0x0F12, 0x000F}, /* #senHal_pContSenModesRegsArray[75][3] 2 70001530 */ + {0x0F12, 0x05AD}, /* #senHal_pContSenModesRegsArray[76][0] 2 70001532 */ + {0x0F12, 0x03DE}, /* #senHal_pContSenModesRegsArray[76][1] 2 70001534 */ + {0x0F12, 0x030A}, /* #senHal_pContSenModesRegsArray[76][2] 2 70001536 */ + {0x0F12, 0x021C}, /* #senHal_pContSenModesRegsArray[76][3] 2 70001538 */ + {0x0F12, 0x062F}, /* #senHal_pContSenModesRegsArray[77][0] 2 7000153A */ + {0x0F12, 0x0460}, /* #senHal_pContSenModesRegsArray[77][1] 2 7000153C */ + {0x0F12, 0x038C}, /* #senHal_pContSenModesRegsArray[77][2] 2 7000153E */ + {0x0F12, 0x029E}, /* #senHal_pContSenModesRegsArray[77][3] 2 70001540 */ + {0x0F12, 0x07FC}, /* #senHal_pContSenModesRegsArray[78][0] 2 70001542 */ + {0x0F12, 0x0847}, /* #senHal_pContSenModesRegsArray[78][1] 2 70001544 */ + {0x0F12, 0x0478}, /* #senHal_pContSenModesRegsArray[78][2] 2 70001546 */ + {0x0F12, 0x04C3}, /* #senHal_pContSenModesRegsArray[78][3] 2 70001548 */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[79][0] 2 7000154A */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[79][1] 2 7000154C */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[79][2] 2 7000154E */ + {0x0F12, 0x0000}, /* #senHal_pContSenModesRegsArray[79][3] 2 70001550 */ + /* Analog Setting END */ + + /* ISP-FE Setting */ + {0x002A, 0x158A}, + {0x0F12, 0xEAF0}, + {0x002A, 0x15C6}, + {0x0F12, 0x0020}, + {0x0F12, 0x0060}, + {0x002A, 0x15BC}, + {0x0F12, 0x0200}, + /* Analog Offset for MSM */ + {0x002A, 0x1608}, + {0x0F12, 0x0100}, /* #gisp_msm_sAnalogOffset[0] */ + {0x0F12, 0x0100}, /* #gisp_msm_sAnalogOffset[1] */ + {0x0F12, 0x0100}, /* #gisp_msm_sAnalogOffset[2] */ + {0x0F12, 0x0100}, /* #gisp_msm_sAnalogOffset[3] */ + /* ISP-FE Setting END */ + + /* ===== Frame rate setting ===== */ + /* How to set */ + /* 1. Exposure value */ + /* dec2hex((1 / (frame rate you want(ms))) * 100d * 4d) */ + /* 2. Analog Digital gain */ + /* dec2hex((Analog gain you want) * 256d) */ + + /* Set preview exposure time */ + {0x002A, 0x0530}, + {0x0F12, 0x3415}, /* #lt_uMaxExp1 */ + {0x0F12, 0x0000}, + {0x0F12, 0x6720}, /* #lt_uMaxExp2 */ + {0x0F12, 0x0000}, + {0x002A, 0x167C}, + {0x0F12, 0x9AB0}, /* #evt1_lt_uMaxExp3 */ + {0x0F12, 0x0000}, + {0x0F12, 0xD055}, /* #evt1_lt_uMaxExp4 */ + {0x0F12, 0x0000}, + + /* Set capture exposure time */ + {0x002A, 0x0538}, + {0x0F12, 0x9C40}, /* #lt_uCapMaxExp1 */ + {0x0F12, 0x0000}, + {0x0F12, 0xD055}, /* #lt_uCapMaxExp2 */ + {0x0F12, 0x0000}, + {0x002A, 0x1684}, + {0x0F12, 0x0360}, /* #evt1_lt_uCapMaxExp3 */ + {0x0F12, 0x0001}, + {0x0F12, 0x3880}, /* #evt1_lt_uCapMaxExp4 */ + {0x0F12, 0x0001}, + + /* Set gain */ + {0x002A, 0x0540}, + {0x0F12, 0x0150}, /* #lt_uMaxAnGain1 */ + {0x0F12, 0x0280}, /* #lt_uMaxAnGain2 */ + {0x002A, 0x168C}, + {0x0F12, 0x02A0}, /* #evt1_lt_uMaxAnGain3 */ + {0x0F12, 0x0700}, /* #evt1_lt_uMaxAnGain4 */ + {0x002A, 0x0544}, + {0x0F12, 0x0100}, /* #lt_uMaxDigGain */ + {0x0F12, 0x1000}, /* #lt_uMaxTotGain */ + {0x002A, 0x1694}, + {0x0F12, 0x0001}, /* #evt1_senHal_bExpandForbid */ + {0x002A, 0x051A}, + {0x0F12, 0x0111}, /* #lt_uLimitHigh */ + {0x0F12, 0x00F0}, /* #lt_uLimitLow */ + {0x002A, 0x0562}, + {0x0F12, 0x0001}, + + /* Set Auto Exposure */ + /* AE target */ + {0x002A, 0x0F70}, + {0x0F12, 0x003A}, /* #TVAR_ae_BrAve */ + /* AE mode */ + {0x002A, 0x0F76}, /* Disable illumination & contrast #ae_StatMode */ + {0x0F12, 0x000F}, + /* AE weight */ + {0x002A, 0x0F7E}, + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_0_ */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_1_ */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_2_ */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_3_ */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_4_ */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_5_ */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_6_ */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_7_ */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_8_ */ + {0x0F12, 0x0303}, /* #ae_WeightTbl_16_9_ */ + {0x0F12, 0x0303}, /* #ae_WeightTbl_16_10 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_11 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_12 */ + {0x0F12, 0x0303}, /* #ae_WeightTbl_16_13 */ + {0x0F12, 0x0303}, /* #ae_WeightTbl_16_14 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_15 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_16 */ + {0x0F12, 0x0303}, /* #ae_WeightTbl_16_17 */ + {0x0F12, 0x0303}, /* #ae_WeightTbl_16_18 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_19 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_20 */ + {0x0F12, 0x0303}, /* #ae_WeightTbl_16_21 */ + {0x0F12, 0x0303}, /* #ae_WeightTbl_16_22 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_23 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_24 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_25 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_26 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_27 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_28 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_29 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_30 */ + {0x0F12, 0x0101}, /* #ae_WeightTbl_16_31 */ + + /* Set Flicker */ + {0x002A, 0x04D2}, + {0x0F12, 0x065F}, /* Anti-flicker disabled */ + {0x002A, 0x04BA}, + {0x0F12, 0x0002}, + {0x002A, 0x0C04}, + {0x0F12, 0xFFFF}, + + /* Set GAS */ + /* GAS alpha */ + /* R, Gr, Gb, B per light source */ + {0x002A, 0x06CE}, + {0x0F12, 0x00ED}, /* #TVAR_ash_GASAlpha[0] Horizon */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[1] */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[2] */ + {0x0F12, 0x00E9}, /* #TVAR_ash_GASAlpha[3] */ + {0x0F12, 0x00ED}, /* #TVAR_ash_GASAlpha[4] IncandA */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[5] */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[6] */ + {0x0F12, 0x00E9}, /* #TVAR_ash_GASAlpha[7] */ + {0x0F12, 0x00ED}, /* #TVAR_ash_GASAlpha[8] WW */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[9] */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[10] */ + {0x0F12, 0x00E9}, /* #TVAR_ash_GASAlpha[11] */ + {0x0F12, 0x00ED}, /* #TVAR_ash_GASAlpha[12] CWF */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[13] */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[14] */ + {0x0F12, 0x00E9}, /* #TVAR_ash_GASAlpha[15] */ + {0x0F12, 0x00ED}, /* #TVAR_ash_GASAlpha[16] D50 */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[17] */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[18] */ + {0x0F12, 0x00E9}, /* #TVAR_ash_GASAlpha[19] */ + {0x0F12, 0x00ED}, /* #TVAR_ash_GASAlpha[20] D65 */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[21] */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[22] */ + {0x0F12, 0x00E9}, /* #TVAR_ash_GASAlpha[23] */ + {0x0F12, 0x00ED}, /* #TVAR_ash_GASAlpha[24] D75 */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[25] */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASAlpha[26] */ + {0x0F12, 0x00E9}, /* #TVAR_ash_GASAlpha[27] */ + {0x0F12, 0x00ED}, /* #TVAR_ash_GASOutdoorAlpha[0] Outdoor*/ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASOutdoorAlpha[1] */ + {0x0F12, 0x00EB}, /* #TVAR_ash_GASOutdoorAlpha[2] */ + {0x0F12, 0x00E9}, /* #TVAR_ash_GASOutdoorAlpha[3] */ + + /* GAS beta */ + {0x0F12, 0x002D}, /* #ash_GASBeta[0] Horizon */ + {0x0F12, 0x0016}, /* #ash_GASBeta[1] */ + {0x0F12, 0x0016}, /* #ash_GASBeta[2] */ + {0x0F12, 0x0000}, /* #ash_GASBeta[3] */ + {0x0F12, 0x002D}, /* #ash_GASBeta[4] IncandA */ + {0x0F12, 0x0016}, /* #ash_GASBeta[5] */ + {0x0F12, 0x0016}, /* #ash_GASBeta[6] */ + {0x0F12, 0x0000}, /* #ash_GASBeta[7] */ + {0x0F12, 0x002D}, /* #ash_GASBeta[8] WW */ + {0x0F12, 0x0016}, /* #ash_GASBeta[9] */ + {0x0F12, 0x0016}, /* #ash_GASBeta[10] */ + {0x0F12, 0x0000}, /* #ash_GASBeta[11] */ + {0x0F12, 0x002D}, /* #ash_GASBeta[12] CWF */ + {0x0F12, 0x0016}, /* #ash_GASBeta[13] */ + {0x0F12, 0x0016}, /* #ash_GASBeta[14] */ + {0x0F12, 0x0000}, /* #ash_GASBeta[15] */ + {0x0F12, 0x002D}, /* #ash_GASBeta[16] D50 */ + {0x0F12, 0x0016}, /* #ash_GASBeta[17] */ + {0x0F12, 0x0016}, /* #ash_GASBeta[18] */ + {0x0F12, 0x0000}, /* #ash_GASBeta[19] */ + {0x0F12, 0x002D}, /* #ash_GASBeta[20] D65 */ + {0x0F12, 0x0016}, /* #ash_GASBeta[21] */ + {0x0F12, 0x0016}, /* #ash_GASBeta[22] */ + {0x0F12, 0x0000}, /* #ash_GASBeta[23] */ + {0x0F12, 0x002D}, /* #ash_GASBeta[24] D75 */ + {0x0F12, 0x0016}, /* #ash_GASBeta[25] */ + {0x0F12, 0x0016}, /* #ash_GASBeta[26] */ + {0x0F12, 0x0000}, /* #ash_GASBeta[27] */ + {0x0F12, 0x002D}, /* #ash_GASOutdoorBeta[0] Outdoor */ + {0x0F12, 0x0016}, /* #ash_GASOutdoorBeta[1] */ + {0x0F12, 0x0016}, /* #ash_GASOutdoorBeta[2] */ + {0x0F12, 0x0000}, /* #ash_GASOutdoorBeta[3] */ + + {0x002A, 0x06B4}, + {0x0F12, 0x0001}, /* #wbt_bUseOutdoorASH ON:1 OFF:0 */ + + /* Parabolic function */ + {0x002A, 0x075A}, + {0x0F12, 0x0000}, /* #ash_bParabolicEstimation */ + {0x0F12, 0x0400}, /* #ash_uParabolicCenterX */ + {0x0F12, 0x0300}, /* #ash_uParabolicCenterY */ + {0x0F12, 0x0010}, /* #ash_uParabolicScalingA */ + {0x0F12, 0x0011}, /* #ash_uParabolicScalingB */ + {0x002A, 0x06C6}, + {0x0F12, 0x00ED}, /* ash_CGrasAlphas_0_ */ + {0x0F12, 0x00EB}, /* ash_CGrasAlphas_1_ */ + {0x0F12, 0x00EB}, /* ash_CGrasAlphas_2_ */ + {0x0F12, 0x00E9}, /* ash_CGrasAlphas_3_ */ + {0x002A, 0x0E3C}, + {0x0F12, 0x00C0}, /* #awbb_Alpha_Comp_Mode */ + {0x002A, 0x074E}, + {0x0F12, 0x0000}, /* #ash_bLumaMode - use Beta : 0001 not use Beta : 0000 */ + /* GAS LUT start address 7000_347C */ + {0x002A, 0x0754}, + {0x0F12, 0x347C}, + {0x0F12, 0x7000}, + + /* GAS LUT - param_start TVAR_ash_pGAS (Change the shading setting) */ + {0x002A, 0x347C}, + {0x0F12, 0x019D}, /* #TVAR_ash_pGAS[0] */ + {0x0F12, 0x0163}, /* #TVAR_ash_pGAS[1] */ + {0x0F12, 0x0137}, /* #TVAR_ash_pGAS[2] */ + {0x0F12, 0x010B}, /* #TVAR_ash_pGAS[3] */ + {0x0F12, 0x00EB}, /* #TVAR_ash_pGAS[4] */ + {0x0F12, 0x00D7}, /* #TVAR_ash_pGAS[5] */ + {0x0F12, 0x00D0}, /* #TVAR_ash_pGAS[6] */ + {0x0F12, 0x00D6}, /* #TVAR_ash_pGAS[7] */ + {0x0F12, 0x00EC}, /* #TVAR_ash_pGAS[8] */ + {0x0F12, 0x0119}, /* #TVAR_ash_pGAS[9] */ + {0x0F12, 0x014C}, /* #TVAR_ash_pGAS[10] */ + {0x0F12, 0x0181}, /* #TVAR_ash_pGAS[11] */ + {0x0F12, 0x01CE}, /* #TVAR_ash_pGAS[12] */ + {0x0F12, 0x017E}, /* #TVAR_ash_pGAS[13] */ + {0x0F12, 0x0149}, /* #TVAR_ash_pGAS[14] */ + {0x0F12, 0x010E}, /* #TVAR_ash_pGAS[15] */ + {0x0F12, 0x00DC}, /* #TVAR_ash_pGAS[16] */ + {0x0F12, 0x00B7}, /* #TVAR_ash_pGAS[17] */ + {0x0F12, 0x00A4}, /* #TVAR_ash_pGAS[18] */ + {0x0F12, 0x009E}, /* #TVAR_ash_pGAS[19] */ + {0x0F12, 0x00A3}, /* #TVAR_ash_pGAS[20] */ + {0x0F12, 0x00BD}, /* #TVAR_ash_pGAS[21] */ + {0x0F12, 0x00E6}, /* #TVAR_ash_pGAS[22] */ + {0x0F12, 0x0125}, /* #TVAR_ash_pGAS[23] */ + {0x0F12, 0x0169}, /* #TVAR_ash_pGAS[24] */ + {0x0F12, 0x019C}, /* #TVAR_ash_pGAS[25] */ + {0x0F12, 0x014F}, /* #TVAR_ash_pGAS[26] */ + {0x0F12, 0x010E}, /* #TVAR_ash_pGAS[27] */ + {0x0F12, 0x00CD}, /* #TVAR_ash_pGAS[28] */ + {0x0F12, 0x009B}, /* #TVAR_ash_pGAS[29] */ + {0x0F12, 0x0076}, /* #TVAR_ash_pGAS[30] */ + {0x0F12, 0x0061}, /* #TVAR_ash_pGAS[31] */ + {0x0F12, 0x0058}, /* #TVAR_ash_pGAS[32] */ + {0x0F12, 0x0063}, /* #TVAR_ash_pGAS[33] */ + {0x0F12, 0x007E}, /* #TVAR_ash_pGAS[34] */ + {0x0F12, 0x00A9}, /* #TVAR_ash_pGAS[35] */ + {0x0F12, 0x00E7}, /* #TVAR_ash_pGAS[36] */ + {0x0F12, 0x0136}, /* #TVAR_ash_pGAS[37] */ + {0x0F12, 0x017E}, /* #TVAR_ash_pGAS[38] */ + {0x0F12, 0x0129}, /* #TVAR_ash_pGAS[39] */ + {0x0F12, 0x00E1}, /* #TVAR_ash_pGAS[40] */ + {0x0F12, 0x009F}, /* #TVAR_ash_pGAS[41] */ + {0x0F12, 0x006B}, /* #TVAR_ash_pGAS[42] */ + {0x0F12, 0x0046}, /* #TVAR_ash_pGAS[43] */ + {0x0F12, 0x0030}, /* #TVAR_ash_pGAS[44] */ + {0x0F12, 0x0029}, /* #TVAR_ash_pGAS[45] */ + {0x0F12, 0x0033}, /* #TVAR_ash_pGAS[46] */ + {0x0F12, 0x004F}, /* #TVAR_ash_pGAS[47] */ + {0x0F12, 0x007F}, /* #TVAR_ash_pGAS[48] */ + {0x0F12, 0x00BD}, /* #TVAR_ash_pGAS[49] */ + {0x0F12, 0x0111}, /* #TVAR_ash_pGAS[50] */ + {0x0F12, 0x015D}, /* #TVAR_ash_pGAS[51] */ + {0x0F12, 0x0110}, /* #TVAR_ash_pGAS[52] */ + {0x0F12, 0x00C6}, /* #TVAR_ash_pGAS[53] */ + {0x0F12, 0x0082}, /* #TVAR_ash_pGAS[54] */ + {0x0F12, 0x004B}, /* #TVAR_ash_pGAS[55] */ + {0x0F12, 0x0026}, /* #TVAR_ash_pGAS[56] */ + {0x0F12, 0x0011}, /* #TVAR_ash_pGAS[57] */ + {0x0F12, 0x000C}, /* #TVAR_ash_pGAS[58] */ + {0x0F12, 0x0016}, /* #TVAR_ash_pGAS[59] */ + {0x0F12, 0x0032}, /* #TVAR_ash_pGAS[60] */ + {0x0F12, 0x0061}, /* #TVAR_ash_pGAS[61] */ + {0x0F12, 0x00A1}, /* #TVAR_ash_pGAS[62] */ + {0x0F12, 0x00F4}, /* #TVAR_ash_pGAS[63] */ + {0x0F12, 0x014C}, /* #TVAR_ash_pGAS[64] */ + {0x0F12, 0x0102}, /* #TVAR_ash_pGAS[65] */ + {0x0F12, 0x00BB}, /* #TVAR_ash_pGAS[66] */ + {0x0F12, 0x0075}, /* #TVAR_ash_pGAS[67] */ + {0x0F12, 0x003F}, /* #TVAR_ash_pGAS[68] */ + {0x0F12, 0x0019}, /* #TVAR_ash_pGAS[69] */ + {0x0F12, 0x0005}, /* #TVAR_ash_pGAS[70] */ + {0x0F12, 0x0000}, /* #TVAR_ash_pGAS[71] */ + {0x0F12, 0x000A}, /* #TVAR_ash_pGAS[72] */ + {0x0F12, 0x0025}, /* #TVAR_ash_pGAS[73] */ + {0x0F12, 0x0055}, /* #TVAR_ash_pGAS[74] */ + {0x0F12, 0x0098}, /* #TVAR_ash_pGAS[75] */ + {0x0F12, 0x00EA}, /* #TVAR_ash_pGAS[76] */ + {0x0F12, 0x0143}, /* #TVAR_ash_pGAS[77] */ + {0x0F12, 0x0106}, /* #TVAR_ash_pGAS[78] */ + {0x0F12, 0x00BF}, /* #TVAR_ash_pGAS[79] */ + {0x0F12, 0x007B}, /* #TVAR_ash_pGAS[80] */ + {0x0F12, 0x0043}, /* #TVAR_ash_pGAS[81] */ + {0x0F12, 0x001F}, /* #TVAR_ash_pGAS[82] */ + {0x0F12, 0x000D}, /* #TVAR_ash_pGAS[83] */ + {0x0F12, 0x0006}, /* #TVAR_ash_pGAS[84] */ + {0x0F12, 0x0010}, /* #TVAR_ash_pGAS[85] */ + {0x0F12, 0x002C}, /* #TVAR_ash_pGAS[86] */ + {0x0F12, 0x005D}, /* #TVAR_ash_pGAS[87] */ + {0x0F12, 0x009D}, /* #TVAR_ash_pGAS[88] */ + {0x0F12, 0x00F2}, /* #TVAR_ash_pGAS[89] */ + {0x0F12, 0x0147}, /* #TVAR_ash_pGAS[90] */ + {0x0F12, 0x0115}, /* #TVAR_ash_pGAS[91] */ + {0x0F12, 0x00D2}, /* #TVAR_ash_pGAS[92] */ + {0x0F12, 0x008C}, /* #TVAR_ash_pGAS[93] */ + {0x0F12, 0x0059}, /* #TVAR_ash_pGAS[94] */ + {0x0F12, 0x0034}, /* #TVAR_ash_pGAS[95] */ + {0x0F12, 0x0022}, /* #TVAR_ash_pGAS[96] */ + {0x0F12, 0x001B}, /* #TVAR_ash_pGAS[97] */ + {0x0F12, 0x0027}, /* #TVAR_ash_pGAS[98] */ + {0x0F12, 0x0047}, /* #TVAR_ash_pGAS[99] */ + {0x0F12, 0x0077}, /* #TVAR_ash_pGAS[100] */ + {0x0F12, 0x00B6}, /* #TVAR_ash_pGAS[101] */ + {0x0F12, 0x0108}, /* #TVAR_ash_pGAS[102] */ + {0x0F12, 0x015F}, /* #TVAR_ash_pGAS[103] */ + {0x0F12, 0x0136}, /* #TVAR_ash_pGAS[104] */ + {0x0F12, 0x00F1}, /* #TVAR_ash_pGAS[105] */ + {0x0F12, 0x00AE}, /* #TVAR_ash_pGAS[106] */ + {0x0F12, 0x007C}, /* #TVAR_ash_pGAS[107] */ + {0x0F12, 0x0058}, /* #TVAR_ash_pGAS[108] */ + {0x0F12, 0x0046}, /* #TVAR_ash_pGAS[109] */ + {0x0F12, 0x0040}, /* #TVAR_ash_pGAS[110] */ + {0x0F12, 0x004E}, /* #TVAR_ash_pGAS[111] */ + {0x0F12, 0x006C}, /* #TVAR_ash_pGAS[112] */ + {0x0F12, 0x009C}, /* #TVAR_ash_pGAS[113] */ + {0x0F12, 0x00DB}, /* #TVAR_ash_pGAS[114] */ + {0x0F12, 0x012F}, /* #TVAR_ash_pGAS[115] */ + {0x0F12, 0x017C}, /* #TVAR_ash_pGAS[116] */ + {0x0F12, 0x015C}, /* #TVAR_ash_pGAS[117] */ + {0x0F12, 0x0120}, /* #TVAR_ash_pGAS[118] */ + {0x0F12, 0x00DF}, /* #TVAR_ash_pGAS[119] */ + {0x0F12, 0x00AF}, /* #TVAR_ash_pGAS[120] */ + {0x0F12, 0x008F}, /* #TVAR_ash_pGAS[121] */ + {0x0F12, 0x007D}, /* #TVAR_ash_pGAS[122] */ + {0x0F12, 0x0079}, /* #TVAR_ash_pGAS[123] */ + {0x0F12, 0x0084}, /* #TVAR_ash_pGAS[124] */ + {0x0F12, 0x00A3}, /* #TVAR_ash_pGAS[125] */ + {0x0F12, 0x00D1}, /* #TVAR_ash_pGAS[126] */ + {0x0F12, 0x0110}, /* #TVAR_ash_pGAS[127] */ + {0x0F12, 0x015E}, /* #TVAR_ash_pGAS[128] */ + {0x0F12, 0x019A}, /* #TVAR_ash_pGAS[129] */ + {0x0F12, 0x0178}, /* #TVAR_ash_pGAS[130] */ + {0x0F12, 0x0144}, /* #TVAR_ash_pGAS[131] */ + {0x0F12, 0x010C}, /* #TVAR_ash_pGAS[132] */ + {0x0F12, 0x00DF}, /* #TVAR_ash_pGAS[133] */ + {0x0F12, 0x00C1}, /* #TVAR_ash_pGAS[134] */ + {0x0F12, 0x00B3}, /* #TVAR_ash_pGAS[135] */ + {0x0F12, 0x00B0}, /* #TVAR_ash_pGAS[136] */ + {0x0F12, 0x00BC}, /* #TVAR_ash_pGAS[137] */ + {0x0F12, 0x00D6}, /* #TVAR_ash_pGAS[138] */ + {0x0F12, 0x0103}, /* #TVAR_ash_pGAS[139] */ + {0x0F12, 0x0144}, /* #TVAR_ash_pGAS[140] */ + {0x0F12, 0x0187}, /* #TVAR_ash_pGAS[141] */ + {0x0F12, 0x01C2}, /* #TVAR_ash_pGAS[142] */ + {0x0F12, 0x0167}, /* #TVAR_ash_pGAS[143] */ + {0x0F12, 0x013A}, /* #TVAR_ash_pGAS[144] */ + {0x0F12, 0x010D}, /* #TVAR_ash_pGAS[145] */ + {0x0F12, 0x00E5}, /* #TVAR_ash_pGAS[146] */ + {0x0F12, 0x00C6}, /* #TVAR_ash_pGAS[147] */ + {0x0F12, 0x00B7}, /* #TVAR_ash_pGAS[148] */ + {0x0F12, 0x00B0}, /* #TVAR_ash_pGAS[149] */ + {0x0F12, 0x00B6}, /* #TVAR_ash_pGAS[150] */ + {0x0F12, 0x00C9}, /* #TVAR_ash_pGAS[151] */ + {0x0F12, 0x00EC}, /* #TVAR_ash_pGAS[152] */ + {0x0F12, 0x011C}, /* #TVAR_ash_pGAS[153] */ + {0x0F12, 0x014B}, /* #TVAR_ash_pGAS[154] */ + {0x0F12, 0x0192}, /* #TVAR_ash_pGAS[155] */ + {0x0F12, 0x0155}, /* #TVAR_ash_pGAS[156] */ + {0x0F12, 0x0125}, /* #TVAR_ash_pGAS[157] */ + {0x0F12, 0x00EE}, /* #TVAR_ash_pGAS[158] */ + {0x0F12, 0x00BF}, /* #TVAR_ash_pGAS[159] */ + {0x0F12, 0x00A2}, /* #TVAR_ash_pGAS[160] */ + {0x0F12, 0x008D}, /* #TVAR_ash_pGAS[161] */ + {0x0F12, 0x0087}, /* #TVAR_ash_pGAS[162] */ + {0x0F12, 0x008F}, /* #TVAR_ash_pGAS[163] */ + {0x0F12, 0x00A1}, /* #TVAR_ash_pGAS[164] */ + {0x0F12, 0x00C5}, /* #TVAR_ash_pGAS[165] */ + {0x0F12, 0x00F8}, /* #TVAR_ash_pGAS[166] */ + {0x0F12, 0x0135}, /* #TVAR_ash_pGAS[167] */ + {0x0F12, 0x0166}, /* #TVAR_ash_pGAS[168] */ + {0x0F12, 0x012F}, /* #TVAR_ash_pGAS[169] */ + {0x0F12, 0x00F2}, /* #TVAR_ash_pGAS[170] */ + {0x0F12, 0x00B6}, /* #TVAR_ash_pGAS[171] */ + {0x0F12, 0x0089}, /* #TVAR_ash_pGAS[172] */ + {0x0F12, 0x0068}, /* #TVAR_ash_pGAS[173] */ + {0x0F12, 0x0055}, /* #TVAR_ash_pGAS[174] */ + {0x0F12, 0x004F}, /* #TVAR_ash_pGAS[175] */ + {0x0F12, 0x0058}, /* #TVAR_ash_pGAS[176] */ + {0x0F12, 0x006E}, /* #TVAR_ash_pGAS[177] */ + {0x0F12, 0x0092}, /* #TVAR_ash_pGAS[178] */ + {0x0F12, 0x00C5}, /* #TVAR_ash_pGAS[179] */ + {0x0F12, 0x0109}, /* #TVAR_ash_pGAS[180] */ + {0x0F12, 0x0147}, /* #TVAR_ash_pGAS[181] */ + {0x0F12, 0x010D}, /* #TVAR_ash_pGAS[182] */ + {0x0F12, 0x00C9}, /* #TVAR_ash_pGAS[183] */ + {0x0F12, 0x008E}, /* #TVAR_ash_pGAS[184] */ + {0x0F12, 0x0061}, /* #TVAR_ash_pGAS[185] */ + {0x0F12, 0x003E}, /* #TVAR_ash_pGAS[186] */ + {0x0F12, 0x002A}, /* #TVAR_ash_pGAS[187] */ + {0x0F12, 0x0025}, /* #TVAR_ash_pGAS[188] */ + {0x0F12, 0x002F}, /* #TVAR_ash_pGAS[189] */ + {0x0F12, 0x0047}, /* #TVAR_ash_pGAS[190] */ + {0x0F12, 0x006F}, /* #TVAR_ash_pGAS[191] */ + {0x0F12, 0x00A2}, /* #TVAR_ash_pGAS[192] */ + {0x0F12, 0x00E9}, /* #TVAR_ash_pGAS[193] */ + {0x0F12, 0x0130}, /* #TVAR_ash_pGAS[194] */ + {0x0F12, 0x00F3}, /* #TVAR_ash_pGAS[195] */ + {0x0F12, 0x00B1}, /* #TVAR_ash_pGAS[196] */ + {0x0F12, 0x0076}, /* #TVAR_ash_pGAS[197] */ + {0x0F12, 0x0045}, /* #TVAR_ash_pGAS[198] */ + {0x0F12, 0x0022}, /* #TVAR_ash_pGAS[199] */ + {0x0F12, 0x000F}, /* #TVAR_ash_pGAS[200] */ + {0x0F12, 0x000A}, /* #TVAR_ash_pGAS[201] */ + {0x0F12, 0x0015}, /* #TVAR_ash_pGAS[202] */ + {0x0F12, 0x002E}, /* #TVAR_ash_pGAS[203] */ + {0x0F12, 0x0058}, /* #TVAR_ash_pGAS[204] */ + {0x0F12, 0x008D}, /* #TVAR_ash_pGAS[205] */ + {0x0F12, 0x00D4}, /* #TVAR_ash_pGAS[206] */ + {0x0F12, 0x011A}, /* #TVAR_ash_pGAS[207] */ + {0x0F12, 0x00E9}, /* #TVAR_ash_pGAS[208] */ + {0x0F12, 0x00A7}, /* #TVAR_ash_pGAS[209] */ + {0x0F12, 0x0068}, /* #TVAR_ash_pGAS[210] */ + {0x0F12, 0x0038}, /* #TVAR_ash_pGAS[211] */ + {0x0F12, 0x0017}, /* #TVAR_ash_pGAS[212] */ + {0x0F12, 0x0004}, /* #TVAR_ash_pGAS[213] */ + {0x0F12, 0x0000}, /* #TVAR_ash_pGAS[214] */ + {0x0F12, 0x000B}, /* #TVAR_ash_pGAS[215] */ + {0x0F12, 0x0025}, /* #TVAR_ash_pGAS[216] */ + {0x0F12, 0x004F}, /* #TVAR_ash_pGAS[217] */ + {0x0F12, 0x0084}, /* #TVAR_ash_pGAS[218] */ + {0x0F12, 0x00CB}, /* #TVAR_ash_pGAS[219] */ + {0x0F12, 0x0117}, /* #TVAR_ash_pGAS[220] */ + {0x0F12, 0x00EA}, /* #TVAR_ash_pGAS[221] */ + {0x0F12, 0x00A8}, /* #TVAR_ash_pGAS[222] */ + {0x0F12, 0x006E}, /* #TVAR_ash_pGAS[223] */ + {0x0F12, 0x003D}, /* #TVAR_ash_pGAS[224] */ + {0x0F12, 0x001B}, /* #TVAR_ash_pGAS[225] */ + {0x0F12, 0x0009}, /* #TVAR_ash_pGAS[226] */ + {0x0F12, 0x0006}, /* #TVAR_ash_pGAS[227] */ + {0x0F12, 0x0010}, /* #TVAR_ash_pGAS[228] */ + {0x0F12, 0x002B}, /* #TVAR_ash_pGAS[229] */ + {0x0F12, 0x0056}, /* #TVAR_ash_pGAS[230] */ + {0x0F12, 0x008B}, /* #TVAR_ash_pGAS[231] */ + {0x0F12, 0x00D1}, /* #TVAR_ash_pGAS[232] */ + {0x0F12, 0x011B}, /* #TVAR_ash_pGAS[233] */ + {0x0F12, 0x00F9}, /* #TVAR_ash_pGAS[234] */ + {0x0F12, 0x00B6}, /* #TVAR_ash_pGAS[235] */ + {0x0F12, 0x007D}, /* #TVAR_ash_pGAS[236] */ + {0x0F12, 0x004E}, /* #TVAR_ash_pGAS[237] */ + {0x0F12, 0x002D}, /* #TVAR_ash_pGAS[238] */ + {0x0F12, 0x001C}, /* #TVAR_ash_pGAS[239] */ + {0x0F12, 0x0019}, /* #TVAR_ash_pGAS[240] */ + {0x0F12, 0x0025}, /* #TVAR_ash_pGAS[241] */ + {0x0F12, 0x0042}, /* #TVAR_ash_pGAS[242] */ + {0x0F12, 0x006C}, /* #TVAR_ash_pGAS[243] */ + {0x0F12, 0x00A0}, /* #TVAR_ash_pGAS[244] */ + {0x0F12, 0x00E6}, /* #TVAR_ash_pGAS[245] */ + {0x0F12, 0x0130}, /* #TVAR_ash_pGAS[246] */ + {0x0F12, 0x0114}, /* #TVAR_ash_pGAS[247] */ + {0x0F12, 0x00D5}, /* #TVAR_ash_pGAS[248] */ + {0x0F12, 0x0099}, /* #TVAR_ash_pGAS[249] */ + {0x0F12, 0x006D}, /* #TVAR_ash_pGAS[250] */ + {0x0F12, 0x004E}, /* #TVAR_ash_pGAS[251] */ + {0x0F12, 0x003E}, /* #TVAR_ash_pGAS[252] */ + {0x0F12, 0x003C}, /* #TVAR_ash_pGAS[253] */ + {0x0F12, 0x0049}, /* #TVAR_ash_pGAS[254] */ + {0x0F12, 0x0065}, /* #TVAR_ash_pGAS[255] */ + {0x0F12, 0x008D}, /* #TVAR_ash_pGAS[256] */ + {0x0F12, 0x00C2}, /* #TVAR_ash_pGAS[257] */ + {0x0F12, 0x0109}, /* #TVAR_ash_pGAS[258] */ + {0x0F12, 0x014C}, /* #TVAR_ash_pGAS[259] */ + {0x0F12, 0x0135}, /* #TVAR_ash_pGAS[260] */ + {0x0F12, 0x00FC}, /* #TVAR_ash_pGAS[261] */ + {0x0F12, 0x00C2}, /* #TVAR_ash_pGAS[262] */ + {0x0F12, 0x0099}, /* #TVAR_ash_pGAS[263] */ + {0x0F12, 0x007D}, /* #TVAR_ash_pGAS[264] */ + {0x0F12, 0x006F}, /* #TVAR_ash_pGAS[265] */ + {0x0F12, 0x006D}, /* #TVAR_ash_pGAS[266] */ + {0x0F12, 0x007C}, /* #TVAR_ash_pGAS[267] */ + {0x0F12, 0x0095}, /* #TVAR_ash_pGAS[268] */ + {0x0F12, 0x00BC}, /* #TVAR_ash_pGAS[269] */ + {0x0F12, 0x00F1}, /* #TVAR_ash_pGAS[270] */ + {0x0F12, 0x0135}, /* #TVAR_ash_pGAS[271] */ + {0x0F12, 0x016E}, /* #TVAR_ash_pGAS[272] */ + {0x0F12, 0x0154}, /* #TVAR_ash_pGAS[273] */ + {0x0F12, 0x011D}, /* #TVAR_ash_pGAS[274] */ + {0x0F12, 0x00E9}, /* #TVAR_ash_pGAS[275] */ + {0x0F12, 0x00C2}, /* #TVAR_ash_pGAS[276] */ + {0x0F12, 0x00A7}, /* #TVAR_ash_pGAS[277] */ + {0x0F12, 0x009C}, /* #TVAR_ash_pGAS[278] */ + {0x0F12, 0x009B}, /* #TVAR_ash_pGAS[279] */ + {0x0F12, 0x00A8}, /* #TVAR_ash_pGAS[280] */ + {0x0F12, 0x00C2}, /* #TVAR_ash_pGAS[281] */ + {0x0F12, 0x00E8}, /* #TVAR_ash_pGAS[282] */ + {0x0F12, 0x011C}, /* #TVAR_ash_pGAS[283] */ + {0x0F12, 0x015C}, /* #TVAR_ash_pGAS[284] */ + {0x0F12, 0x018F}, /* #TVAR_ash_pGAS[285] */ + {0x0F12, 0x0158}, /* #TVAR_ash_pGAS[286] */ + {0x0F12, 0x012B}, /* #TVAR_ash_pGAS[287] */ + {0x0F12, 0x0100}, /* #TVAR_ash_pGAS[288] */ + {0x0F12, 0x00DA}, /* #TVAR_ash_pGAS[289] */ + {0x0F12, 0x00BF}, /* #TVAR_ash_pGAS[290] */ + {0x0F12, 0x00AE}, /* #TVAR_ash_pGAS[291] */ + {0x0F12, 0x00AD}, /* #TVAR_ash_pGAS[292] */ + {0x0F12, 0x00B8}, /* #TVAR_ash_pGAS[293] */ + {0x0F12, 0x00D2}, /* #TVAR_ash_pGAS[294] */ + {0x0F12, 0x00FB}, /* #TVAR_ash_pGAS[295] */ + {0x0F12, 0x012C}, /* #TVAR_ash_pGAS[296] */ + {0x0F12, 0x015B}, /* #TVAR_ash_pGAS[297] */ + {0x0F12, 0x01A0}, /* #TVAR_ash_pGAS[298] */ + {0x0F12, 0x0150}, /* #TVAR_ash_pGAS[299] */ + {0x0F12, 0x011F}, /* #TVAR_ash_pGAS[300] */ + {0x0F12, 0x00E7}, /* #TVAR_ash_pGAS[301] */ + {0x0F12, 0x00BA}, /* #TVAR_ash_pGAS[302] */ + {0x0F12, 0x009D}, /* #TVAR_ash_pGAS[303] */ + {0x0F12, 0x008C}, /* #TVAR_ash_pGAS[304] */ + {0x0F12, 0x008B}, /* #TVAR_ash_pGAS[305] */ + {0x0F12, 0x0095}, /* #TVAR_ash_pGAS[306] */ + {0x0F12, 0x00AF}, /* #TVAR_ash_pGAS[307] */ + {0x0F12, 0x00D6}, /* #TVAR_ash_pGAS[308] */ + {0x0F12, 0x010E}, /* #TVAR_ash_pGAS[309] */ + {0x0F12, 0x014C}, /* #TVAR_ash_pGAS[310] */ + {0x0F12, 0x017C}, /* #TVAR_ash_pGAS[311] */ + {0x0F12, 0x012E}, /* #TVAR_ash_pGAS[312] */ + {0x0F12, 0x00EE}, /* #TVAR_ash_pGAS[313] */ + {0x0F12, 0x00B4}, /* #TVAR_ash_pGAS[314] */ + {0x0F12, 0x0088}, /* #TVAR_ash_pGAS[315] */ + {0x0F12, 0x0068}, /* #TVAR_ash_pGAS[316] */ + {0x0F12, 0x0055}, /* #TVAR_ash_pGAS[317] */ + {0x0F12, 0x0050}, /* #TVAR_ash_pGAS[318] */ + {0x0F12, 0x005E}, /* #TVAR_ash_pGAS[319] */ + {0x0F12, 0x007A}, /* #TVAR_ash_pGAS[320] */ + {0x0F12, 0x00A4}, /* #TVAR_ash_pGAS[321] */ + {0x0F12, 0x00DA}, /* #TVAR_ash_pGAS[322] */ + {0x0F12, 0x0121}, /* #TVAR_ash_pGAS[323] */ + {0x0F12, 0x0161}, /* #TVAR_ash_pGAS[324] */ + {0x0F12, 0x010B}, /* #TVAR_ash_pGAS[325] */ + {0x0F12, 0x00C9}, /* #TVAR_ash_pGAS[326] */ + {0x0F12, 0x008E}, /* #TVAR_ash_pGAS[327] */ + {0x0F12, 0x0061}, /* #TVAR_ash_pGAS[328] */ + {0x0F12, 0x003F}, /* #TVAR_ash_pGAS[329] */ + {0x0F12, 0x002B}, /* #TVAR_ash_pGAS[330] */ + {0x0F12, 0x0028}, /* #TVAR_ash_pGAS[331] */ + {0x0F12, 0x0034}, /* #TVAR_ash_pGAS[332] */ + {0x0F12, 0x0052}, /* #TVAR_ash_pGAS[333] */ + {0x0F12, 0x007D}, /* #TVAR_ash_pGAS[334] */ + {0x0F12, 0x00B4}, /* #TVAR_ash_pGAS[335] */ + {0x0F12, 0x00F9}, /* #TVAR_ash_pGAS[336] */ + {0x0F12, 0x0141}, /* #TVAR_ash_pGAS[337] */ + {0x0F12, 0x00F9}, /* #TVAR_ash_pGAS[338] */ + {0x0F12, 0x00B3}, /* #TVAR_ash_pGAS[339] */ + {0x0F12, 0x0079}, /* #TVAR_ash_pGAS[340] */ + {0x0F12, 0x0048}, /* #TVAR_ash_pGAS[341] */ + {0x0F12, 0x0024}, /* #TVAR_ash_pGAS[342] */ + {0x0F12, 0x0010}, /* #TVAR_ash_pGAS[343] */ + {0x0F12, 0x000C}, /* #TVAR_ash_pGAS[344] */ + {0x0F12, 0x0018}, /* #TVAR_ash_pGAS[345] */ + {0x0F12, 0x0035}, /* #TVAR_ash_pGAS[346] */ + {0x0F12, 0x0062}, /* #TVAR_ash_pGAS[347] */ + {0x0F12, 0x009A}, /* #TVAR_ash_pGAS[348] */ + {0x0F12, 0x00DF}, /* #TVAR_ash_pGAS[349] */ + {0x0F12, 0x0128}, /* #TVAR_ash_pGAS[350] */ + {0x0F12, 0x00F2}, /* #TVAR_ash_pGAS[351] */ + {0x0F12, 0x00AE}, /* #TVAR_ash_pGAS[352] */ + {0x0F12, 0x0071}, /* #TVAR_ash_pGAS[353] */ + {0x0F12, 0x003E}, /* #TVAR_ash_pGAS[354] */ + {0x0F12, 0x001B}, /* #TVAR_ash_pGAS[355] */ + {0x0F12, 0x0005}, /* #TVAR_ash_pGAS[356] */ + {0x0F12, 0x0000}, /* #TVAR_ash_pGAS[357] */ + {0x0F12, 0x000C}, /* #TVAR_ash_pGAS[358] */ + {0x0F12, 0x0029}, /* #TVAR_ash_pGAS[359] */ + {0x0F12, 0x0053}, /* #TVAR_ash_pGAS[360] */ + {0x0F12, 0x008A}, /* #TVAR_ash_pGAS[361] */ + {0x0F12, 0x00D1}, /* #TVAR_ash_pGAS[362] */ + {0x0F12, 0x0118}, /* #TVAR_ash_pGAS[363] */ + {0x0F12, 0x00F4}, /* #TVAR_ash_pGAS[364] */ + {0x0F12, 0x00B2}, /* #TVAR_ash_pGAS[365] */ + {0x0F12, 0x0076}, /* #TVAR_ash_pGAS[366] */ + {0x0F12, 0x0044}, /* #TVAR_ash_pGAS[367] */ + {0x0F12, 0x0020}, /* #TVAR_ash_pGAS[368] */ + {0x0F12, 0x000B}, /* #TVAR_ash_pGAS[369] */ + {0x0F12, 0x0005}, /* #TVAR_ash_pGAS[370] */ + {0x0F12, 0x000F}, /* #TVAR_ash_pGAS[371] */ + {0x0F12, 0x002C}, /* #TVAR_ash_pGAS[372] */ + {0x0F12, 0x0055}, /* #TVAR_ash_pGAS[373] */ + {0x0F12, 0x008A}, /* #TVAR_ash_pGAS[374] */ + {0x0F12, 0x00CF}, /* #TVAR_ash_pGAS[375] */ + {0x0F12, 0x0117}, /* #TVAR_ash_pGAS[376] */ + {0x0F12, 0x0106}, /* #TVAR_ash_pGAS[377] */ + {0x0F12, 0x00C2}, /* #TVAR_ash_pGAS[378] */ + {0x0F12, 0x0088}, /* #TVAR_ash_pGAS[379] */ + {0x0F12, 0x0057}, /* #TVAR_ash_pGAS[380] */ + {0x0F12, 0x0033}, /* #TVAR_ash_pGAS[381] */ + {0x0F12, 0x001F}, /* #TVAR_ash_pGAS[382] */ + {0x0F12, 0x0017}, /* #TVAR_ash_pGAS[383] */ + {0x0F12, 0x0021}, /* #TVAR_ash_pGAS[384] */ + {0x0F12, 0x003C}, /* #TVAR_ash_pGAS[385] */ + {0x0F12, 0x0065}, /* #TVAR_ash_pGAS[386] */ + {0x0F12, 0x0099}, /* #TVAR_ash_pGAS[387] */ + {0x0F12, 0x00DC}, /* #TVAR_ash_pGAS[388] */ + {0x0F12, 0x0125}, /* #TVAR_ash_pGAS[389] */ + {0x0F12, 0x0125}, /* #TVAR_ash_pGAS[390] */ + {0x0F12, 0x00E2}, /* #TVAR_ash_pGAS[391] */ + {0x0F12, 0x00A4}, /* #TVAR_ash_pGAS[392] */ + {0x0F12, 0x0077}, /* #TVAR_ash_pGAS[393] */ + {0x0F12, 0x0053}, /* #TVAR_ash_pGAS[394] */ + {0x0F12, 0x003F}, /* #TVAR_ash_pGAS[395] */ + {0x0F12, 0x0038}, /* #TVAR_ash_pGAS[396] */ + {0x0F12, 0x0042}, /* #TVAR_ash_pGAS[397] */ + {0x0F12, 0x005B}, /* #TVAR_ash_pGAS[398] */ + {0x0F12, 0x0081}, /* #TVAR_ash_pGAS[399] */ + {0x0F12, 0x00B3}, /* #TVAR_ash_pGAS[400] */ + {0x0F12, 0x00F8}, /* #TVAR_ash_pGAS[401] */ + {0x0F12, 0x013D}, /* #TVAR_ash_pGAS[402] */ + {0x0F12, 0x0148}, /* #TVAR_ash_pGAS[403] */ + {0x0F12, 0x010C}, /* #TVAR_ash_pGAS[404] */ + {0x0F12, 0x00D2}, /* #TVAR_ash_pGAS[405] */ + {0x0F12, 0x00A4}, /* #TVAR_ash_pGAS[406] */ + {0x0F12, 0x0084}, /* #TVAR_ash_pGAS[407] */ + {0x0F12, 0x0071}, /* #TVAR_ash_pGAS[408] */ + {0x0F12, 0x006A}, /* #TVAR_ash_pGAS[409] */ + {0x0F12, 0x0072}, /* #TVAR_ash_pGAS[410] */ + {0x0F12, 0x0089}, /* #TVAR_ash_pGAS[411] */ + {0x0F12, 0x00AC}, /* #TVAR_ash_pGAS[412] */ + {0x0F12, 0x00DE}, /* #TVAR_ash_pGAS[413] */ + {0x0F12, 0x011E}, /* #TVAR_ash_pGAS[414] */ + {0x0F12, 0x015A}, /* #TVAR_ash_pGAS[415] */ + {0x0F12, 0x0167}, /* #TVAR_ash_pGAS[416] */ + {0x0F12, 0x0130}, /* #TVAR_ash_pGAS[417] */ + {0x0F12, 0x00FC}, /* #TVAR_ash_pGAS[418] */ + {0x0F12, 0x00D1}, /* #TVAR_ash_pGAS[419] */ + {0x0F12, 0x00B5}, /* #TVAR_ash_pGAS[420] */ + {0x0F12, 0x00A2}, /* #TVAR_ash_pGAS[421] */ + {0x0F12, 0x009D}, /* #TVAR_ash_pGAS[422] */ + {0x0F12, 0x00A2}, /* #TVAR_ash_pGAS[423] */ + {0x0F12, 0x00B8}, /* #TVAR_ash_pGAS[424] */ + {0x0F12, 0x00D9}, /* #TVAR_ash_pGAS[425] */ + {0x0F12, 0x0106}, /* #TVAR_ash_pGAS[426] */ + {0x0F12, 0x0140}, /* #TVAR_ash_pGAS[427] */ + {0x0F12, 0x0174}, /* #TVAR_ash_pGAS[428] */ + {0x0F12, 0x0139}, /* #TVAR_ash_pGAS[429] */ + {0x0F12, 0x0111}, /* #TVAR_ash_pGAS[430] */ + {0x0F12, 0x00EC}, /* #TVAR_ash_pGAS[431] */ + {0x0F12, 0x00C6}, /* #TVAR_ash_pGAS[432] */ + {0x0F12, 0x00AF}, /* #TVAR_ash_pGAS[433] */ + {0x0F12, 0x00A4}, /* #TVAR_ash_pGAS[434] */ + {0x0F12, 0x00A2}, /* #TVAR_ash_pGAS[435] */ + {0x0F12, 0x00AD}, /* #TVAR_ash_pGAS[436] */ + {0x0F12, 0x00C2}, /* #TVAR_ash_pGAS[437] */ + {0x0F12, 0x00E6}, /* #TVAR_ash_pGAS[438] */ + {0x0F12, 0x0111}, /* #TVAR_ash_pGAS[439] */ + {0x0F12, 0x0141}, /* #TVAR_ash_pGAS[440] */ + {0x0F12, 0x017D}, /* #TVAR_ash_pGAS[441] */ + {0x0F12, 0x012B}, /* #TVAR_ash_pGAS[442] */ + {0x0F12, 0x00FF}, /* #TVAR_ash_pGAS[443] */ + {0x0F12, 0x00CD}, /* #TVAR_ash_pGAS[444] */ + {0x0F12, 0x00A5}, /* #TVAR_ash_pGAS[445] */ + {0x0F12, 0x008F}, /* #TVAR_ash_pGAS[446] */ + {0x0F12, 0x0082}, /* #TVAR_ash_pGAS[447] */ + {0x0F12, 0x0082}, /* #TVAR_ash_pGAS[448] */ + {0x0F12, 0x0089}, /* #TVAR_ash_pGAS[449] */ + {0x0F12, 0x00A0}, /* #TVAR_ash_pGAS[450] */ + {0x0F12, 0x00C2}, /* #TVAR_ash_pGAS[451] */ + {0x0F12, 0x00F2}, /* #TVAR_ash_pGAS[452] */ + {0x0F12, 0x012C}, /* #TVAR_ash_pGAS[453] */ + {0x0F12, 0x0156}, /* #TVAR_ash_pGAS[454] */ + {0x0F12, 0x0102}, /* #TVAR_ash_pGAS[455] */ + {0x0F12, 0x00CB}, /* #TVAR_ash_pGAS[456] */ + {0x0F12, 0x009B}, /* #TVAR_ash_pGAS[457] */ + {0x0F12, 0x0075}, /* #TVAR_ash_pGAS[458] */ + {0x0F12, 0x005D}, /* #TVAR_ash_pGAS[459] */ + {0x0F12, 0x004F}, /* #TVAR_ash_pGAS[460] */ + {0x0F12, 0x004E}, /* #TVAR_ash_pGAS[461] */ + {0x0F12, 0x0059}, /* #TVAR_ash_pGAS[462] */ + {0x0F12, 0x006F}, /* #TVAR_ash_pGAS[463] */ + {0x0F12, 0x0091}, /* #TVAR_ash_pGAS[464] */ + {0x0F12, 0x00BE}, /* #TVAR_ash_pGAS[465] */ + {0x0F12, 0x00FD}, /* #TVAR_ash_pGAS[466] */ + {0x0F12, 0x0134}, /* #TVAR_ash_pGAS[467] */ + {0x0F12, 0x00E1}, /* #TVAR_ash_pGAS[468] */ + {0x0F12, 0x00A5}, /* #TVAR_ash_pGAS[469] */ + {0x0F12, 0x0075}, /* #TVAR_ash_pGAS[470] */ + {0x0F12, 0x004F}, /* #TVAR_ash_pGAS[471] */ + {0x0F12, 0x0035}, /* #TVAR_ash_pGAS[472] */ + {0x0F12, 0x0028}, /* #TVAR_ash_pGAS[473] */ + {0x0F12, 0x0025}, /* #TVAR_ash_pGAS[474] */ + {0x0F12, 0x0030}, /* #TVAR_ash_pGAS[475] */ + {0x0F12, 0x0048}, /* #TVAR_ash_pGAS[476] */ + {0x0F12, 0x006C}, /* #TVAR_ash_pGAS[477] */ + {0x0F12, 0x009A}, /* #TVAR_ash_pGAS[478] */ + {0x0F12, 0x00D6}, /* #TVAR_ash_pGAS[479] */ + {0x0F12, 0x0119}, /* #TVAR_ash_pGAS[480] */ + {0x0F12, 0x00CA}, /* #TVAR_ash_pGAS[481] */ + {0x0F12, 0x0090}, /* #TVAR_ash_pGAS[482] */ + {0x0F12, 0x005C}, /* #TVAR_ash_pGAS[483] */ + {0x0F12, 0x0036}, /* #TVAR_ash_pGAS[484] */ + {0x0F12, 0x001B}, /* #TVAR_ash_pGAS[485] */ + {0x0F12, 0x000D}, /* #TVAR_ash_pGAS[486] */ + {0x0F12, 0x000B}, /* #TVAR_ash_pGAS[487] */ + {0x0F12, 0x0015}, /* #TVAR_ash_pGAS[488] */ + {0x0F12, 0x002A}, /* #TVAR_ash_pGAS[489] */ + {0x0F12, 0x004F}, /* #TVAR_ash_pGAS[490] */ + {0x0F12, 0x007C}, /* #TVAR_ash_pGAS[491] */ + {0x0F12, 0x00B9}, /* #TVAR_ash_pGAS[492] */ + {0x0F12, 0x00FA}, /* #TVAR_ash_pGAS[493] */ + {0x0F12, 0x00BF}, /* #TVAR_ash_pGAS[494] */ + {0x0F12, 0x0086}, /* #TVAR_ash_pGAS[495] */ + {0x0F12, 0x0053}, /* #TVAR_ash_pGAS[496] */ + {0x0F12, 0x002C}, /* #TVAR_ash_pGAS[497] */ + {0x0F12, 0x0010}, /* #TVAR_ash_pGAS[498] */ + {0x0F12, 0x0002}, /* #TVAR_ash_pGAS[499] */ + {0x0F12, 0x0000}, /* #TVAR_ash_pGAS[500] */ + {0x0F12, 0x0007}, /* #TVAR_ash_pGAS[501] */ + {0x0F12, 0x001D}, /* #TVAR_ash_pGAS[502] */ + {0x0F12, 0x0040}, /* #TVAR_ash_pGAS[503] */ + {0x0F12, 0x006B}, /* #TVAR_ash_pGAS[504] */ + {0x0F12, 0x00A8}, /* #TVAR_ash_pGAS[505] */ + {0x0F12, 0x00EC}, /* #TVAR_ash_pGAS[506] */ + {0x0F12, 0x00C4}, /* #TVAR_ash_pGAS[507] */ + {0x0F12, 0x0089}, /* #TVAR_ash_pGAS[508] */ + {0x0F12, 0x0057}, /* #TVAR_ash_pGAS[509] */ + {0x0F12, 0x002F}, /* #TVAR_ash_pGAS[510] */ + {0x0F12, 0x0015}, /* #TVAR_ash_pGAS[511] */ + {0x0F12, 0x0008}, /* #TVAR_ash_pGAS[512] */ + {0x0F12, 0x0003}, /* #TVAR_ash_pGAS[513] */ + {0x0F12, 0x000B}, /* #TVAR_ash_pGAS[514] */ + {0x0F12, 0x001E}, /* #TVAR_ash_pGAS[515] */ + {0x0F12, 0x003F}, /* #TVAR_ash_pGAS[516] */ + {0x0F12, 0x006B}, /* #TVAR_ash_pGAS[517] */ + {0x0F12, 0x00A6}, /* #TVAR_ash_pGAS[518] */ + {0x0F12, 0x00E5}, /* #TVAR_ash_pGAS[519] */ + {0x0F12, 0x00D2}, /* #TVAR_ash_pGAS[520] */ + {0x0F12, 0x0097}, /* #TVAR_ash_pGAS[521] */ + {0x0F12, 0x0065}, /* #TVAR_ash_pGAS[522] */ + {0x0F12, 0x0041}, /* #TVAR_ash_pGAS[523] */ + {0x0F12, 0x0027}, /* #TVAR_ash_pGAS[524] */ + {0x0F12, 0x0018}, /* #TVAR_ash_pGAS[525] */ + {0x0F12, 0x0014}, /* #TVAR_ash_pGAS[526] */ + {0x0F12, 0x001A}, /* #TVAR_ash_pGAS[527] */ + {0x0F12, 0x002E}, /* #TVAR_ash_pGAS[528] */ + {0x0F12, 0x004F}, /* #TVAR_ash_pGAS[529] */ + {0x0F12, 0x0076}, /* #TVAR_ash_pGAS[530] */ + {0x0F12, 0x00B3}, /* #TVAR_ash_pGAS[531] */ + {0x0F12, 0x00F1}, /* #TVAR_ash_pGAS[532] */ + {0x0F12, 0x00EE}, /* #TVAR_ash_pGAS[533] */ + {0x0F12, 0x00B3}, /* #TVAR_ash_pGAS[534] */ + {0x0F12, 0x0082}, /* #TVAR_ash_pGAS[535] */ + {0x0F12, 0x005D}, /* #TVAR_ash_pGAS[536] */ + {0x0F12, 0x0043}, /* #TVAR_ash_pGAS[537] */ + {0x0F12, 0x0036}, /* #TVAR_ash_pGAS[538] */ + {0x0F12, 0x0031}, /* #TVAR_ash_pGAS[539] */ + {0x0F12, 0x0037}, /* #TVAR_ash_pGAS[540] */ + {0x0F12, 0x004B}, /* #TVAR_ash_pGAS[541] */ + {0x0F12, 0x0067}, /* #TVAR_ash_pGAS[542] */ + {0x0F12, 0x0092}, /* #TVAR_ash_pGAS[543] */ + {0x0F12, 0x00CD}, /* #TVAR_ash_pGAS[544] */ + {0x0F12, 0x0107}, /* #TVAR_ash_pGAS[545] */ + {0x0F12, 0x0110}, /* #TVAR_ash_pGAS[546] */ + {0x0F12, 0x00DA}, /* #TVAR_ash_pGAS[547] */ + {0x0F12, 0x00AA}, /* #TVAR_ash_pGAS[548] */ + {0x0F12, 0x0086}, /* #TVAR_ash_pGAS[549] */ + {0x0F12, 0x006F}, /* #TVAR_ash_pGAS[550] */ + {0x0F12, 0x0061}, /* #TVAR_ash_pGAS[551] */ + {0x0F12, 0x005B}, /* #TVAR_ash_pGAS[552] */ + {0x0F12, 0x0061}, /* #TVAR_ash_pGAS[553] */ + {0x0F12, 0x0072}, /* #TVAR_ash_pGAS[554] */ + {0x0F12, 0x008D}, /* #TVAR_ash_pGAS[555] */ + {0x0F12, 0x00B6}, /* #TVAR_ash_pGAS[556] */ + {0x0F12, 0x00F1}, /* #TVAR_ash_pGAS[557] */ + {0x0F12, 0x0129}, /* #TVAR_ash_pGAS[558] */ + {0x0F12, 0x0134}, /* #TVAR_ash_pGAS[559] */ + {0x0F12, 0x0102}, /* #TVAR_ash_pGAS[560] */ + {0x0F12, 0x00D2}, /* #TVAR_ash_pGAS[561] */ + {0x0F12, 0x00B0}, /* #TVAR_ash_pGAS[562] */ + {0x0F12, 0x009A}, /* #TVAR_ash_pGAS[563] */ + {0x0F12, 0x008D}, /* #TVAR_ash_pGAS[564] */ + {0x0F12, 0x0089}, /* #TVAR_ash_pGAS[565] */ + {0x0F12, 0x008C}, /* #TVAR_ash_pGAS[566] */ + {0x0F12, 0x0099}, /* #TVAR_ash_pGAS[567] */ + {0x0F12, 0x00B2}, /* #TVAR_ash_pGAS[568] */ + {0x0F12, 0x00D9}, /* #TVAR_ash_pGAS[569] */ + {0x0F12, 0x010E}, /* #TVAR_ash_pGAS[570] */ + {0x0F12, 0x0142}, /* #TVAR_ash_pGAS[571] */ + + {0x002A, 0x0D30}, + {0x0F12, 0x02A7}, /* #awbb_GLocusR */ + {0x0F12, 0x0343}, /* #awbb_GLocusB */ + {0x002A, 0x06B8}, + {0x0F12, 0x00C7}, /* #TVAR_ash_AwbAshCord_0_ */ + {0x0F12, 0x00d9}, /* #TVAR_ash_AwbAshCord_1_ */ + {0x0F12, 0x0110}, /* #TVAR_ash_AwbAshCord_2_ */ + {0x0F12, 0x0129}, /* #TVAR_ash_AwbAshCord_3_ */ + {0x0F12, 0x0159}, /* #TVAR_ash_AwbAshCord_4_ */ + {0x0F12, 0x0179}, /* #TVAR_ash_AwbAshCord_5_ */ + {0x0F12, 0x018c}, /* #TVAR_ash_AwbAshCord_6_ */ + + /* Set CCM */ + /* CCM start address 7000_33A4 */ + {0x002A, 0x0698}, + {0x0F12, 0x33A4}, + {0x0F12, 0x7000}, + {0x002A, 0x33A4}, + {0x0F12, 0x0172}, /* #TVAR_wbt_pBaseCcms[0] Horizon */ + {0x0F12, 0xFF64}, /* #TVAR_wbt_pBaseCcms[1] */ + {0x0F12, 0xFFA0}, /* #TVAR_wbt_pBaseCcms[2] */ + {0x0F12, 0xFF4D}, /* #TVAR_wbt_pBaseCcms[3] */ + {0x0F12, 0x01FA}, /* #TVAR_wbt_pBaseCcms[4] */ + {0x0F12, 0xFEF4}, /* #TVAR_wbt_pBaseCcms[5] */ + {0x0F12, 0xFFD9}, /* #TVAR_wbt_pBaseCcms[6] */ + {0x0F12, 0x0025}, /* #TVAR_wbt_pBaseCcms[7] */ + {0x0F12, 0x026F}, /* #TVAR_wbt_pBaseCcms[8] */ + {0x0F12, 0x0299}, /* #TVAR_wbt_pBaseCcms[9] */ + {0x0F12, 0x012F}, /* #TVAR_wbt_pBaseCcms[10] */ + {0x0F12, 0xFE21}, /* #TVAR_wbt_pBaseCcms[11] */ + {0x0F12, 0x0143}, /* #TVAR_wbt_pBaseCcms[12] */ + {0x0F12, 0xFF4E}, /* #TVAR_wbt_pBaseCcms[13] */ + {0x0F12, 0x0183}, /* #TVAR_wbt_pBaseCcms[14] */ + {0x0F12, 0xFEBA}, /* #TVAR_wbt_pBaseCcms[15] */ + {0x0F12, 0x0191}, /* #TVAR_wbt_pBaseCcms[16] */ + {0x0F12, 0x013D}, /* #TVAR_wbt_pBaseCcms[17] */ + {0x0F12, 0x0172}, /* #TVAR_wbt_pBaseCcms[18] Inca */ + {0x0F12, 0xFF64}, /* #TVAR_wbt_pBaseCcms[19] */ + {0x0F12, 0xFFA0}, /* #TVAR_wbt_pBaseCcms[20] */ + {0x0F12, 0xFF4D}, /* #TVAR_wbt_pBaseCcms[21] */ + {0x0F12, 0x01FA}, /* #TVAR_wbt_pBaseCcms[22] */ + {0x0F12, 0xFEF4}, /* #TVAR_wbt_pBaseCcms[23] */ + {0x0F12, 0xFFD9}, /* #TVAR_wbt_pBaseCcms[24] */ + {0x0F12, 0x0025}, /* #TVAR_wbt_pBaseCcms[25] */ + {0x0F12, 0x026F}, /* #TVAR_wbt_pBaseCcms[26] */ + {0x0F12, 0x0299}, /* #TVAR_wbt_pBaseCcms[27] */ + {0x0F12, 0x012F}, /* #TVAR_wbt_pBaseCcms[28] */ + {0x0F12, 0xFE21}, /* #TVAR_wbt_pBaseCcms[29] */ + {0x0F12, 0x0143}, /* #TVAR_wbt_pBaseCcms[30] */ + {0x0F12, 0xFF4E}, /* #TVAR_wbt_pBaseCcms[31] */ + {0x0F12, 0x0183}, /* #TVAR_wbt_pBaseCcms[32] */ + {0x0F12, 0xFEBA}, /* #TVAR_wbt_pBaseCcms[33] */ + {0x0F12, 0x0191}, /* #TVAR_wbt_pBaseCcms[34] */ + {0x0F12, 0x013D}, /* #TVAR_wbt_pBaseCcms[35] */ + {0x0F12, 0x01C8}, /* #TVAR_wbt_pBaseCcms[36] WW */ + {0x0F12, 0xFF57}, /* #TVAR_wbt_pBaseCcms[37] */ + {0x0F12, 0xFFC3}, /* #TVAR_wbt_pBaseCcms[38] */ + {0x0F12, 0xFF67}, /* #TVAR_wbt_pBaseCcms[39] */ + {0x0F12, 0x01AD}, /* #TVAR_wbt_pBaseCcms[40] */ + {0x0F12, 0xFF39}, /* #TVAR_wbt_pBaseCcms[41] */ + {0x0F12, 0xFFE6}, /* #TVAR_wbt_pBaseCcms[42] */ + {0x0F12, 0xFFF0}, /* #TVAR_wbt_pBaseCcms[43] */ + {0x0F12, 0x01B0}, /* #TVAR_wbt_pBaseCcms[44] */ + {0x0F12, 0x00EF}, /* #TVAR_wbt_pBaseCcms[45] */ + {0x0F12, 0x00EE}, /* #TVAR_wbt_pBaseCcms[46] */ + {0x0F12, 0xFF1D}, /* #TVAR_wbt_pBaseCcms[47] */ + {0x0F12, 0x01A4}, /* #TVAR_wbt_pBaseCcms[48] */ + {0x0F12, 0xFF70}, /* #TVAR_wbt_pBaseCcms[49] */ + {0x0F12, 0x01D0}, /* #TVAR_wbt_pBaseCcms[50] */ + {0x0F12, 0xFF3B}, /* #TVAR_wbt_pBaseCcms[51] */ + {0x0F12, 0x016F}, /* #TVAR_wbt_pBaseCcms[52] */ + {0x0F12, 0x012C}, /* #TVAR_wbt_pBaseCcms[53] */ + {0x0F12, 0x01C8}, /* #TVAR_wbt_pBaseCcms[54] CWF */ + {0x0F12, 0xFF57}, /* #TVAR_wbt_pBaseCcms[55] */ + {0x0F12, 0xFFC3}, /* #TVAR_wbt_pBaseCcms[56] */ + {0x0F12, 0xFF67}, /* #TVAR_wbt_pBaseCcms[57] */ + {0x0F12, 0x01AD}, /* #TVAR_wbt_pBaseCcms[58] */ + {0x0F12, 0xFF39}, /* #TVAR_wbt_pBaseCcms[59] */ + {0x0F12, 0xFFE6}, /* #TVAR_wbt_pBaseCcms[60] */ + {0x0F12, 0xFFF0}, /* #TVAR_wbt_pBaseCcms[61] */ + {0x0F12, 0x01B0}, /* #TVAR_wbt_pBaseCcms[62] */ + {0x0F12, 0x00EF}, /* #TVAR_wbt_pBaseCcms[63] */ + {0x0F12, 0x00EE}, /* #TVAR_wbt_pBaseCcms[64] */ + {0x0F12, 0xFF1D}, /* #TVAR_wbt_pBaseCcms[65] */ + {0x0F12, 0x01A4}, /* #TVAR_wbt_pBaseCcms[66] */ + {0x0F12, 0xFF70}, /* #TVAR_wbt_pBaseCcms[67] */ + {0x0F12, 0x01D0}, /* #TVAR_wbt_pBaseCcms[68] */ + {0x0F12, 0xFF3B}, /* #TVAR_wbt_pBaseCcms[69] */ + {0x0F12, 0x016F}, /* #TVAR_wbt_pBaseCcms[70] */ + {0x0F12, 0x012C}, /* #TVAR_wbt_pBaseCcms[71] */ + {0x0F12, 0x0184}, /* #TVAR_wbt_pBaseCcms[72] D50 */ + {0x0F12, 0xFFA0}, /* #TVAR_wbt_pBaseCcms[73] */ + {0x0F12, 0xFFF4}, /* #TVAR_wbt_pBaseCcms[74] */ + {0x0F12, 0xFF71}, /* #TVAR_wbt_pBaseCcms[75] */ + {0x0F12, 0x019E}, /* #TVAR_wbt_pBaseCcms[76] */ + {0x0F12, 0xFF45}, /* #TVAR_wbt_pBaseCcms[77] */ + {0x0F12, 0xFFFE}, /* #TVAR_wbt_pBaseCcms[78] */ + {0x0F12, 0x0006}, /* #TVAR_wbt_pBaseCcms[79] */ + {0x0F12, 0x018A}, /* #TVAR_wbt_pBaseCcms[80] */ + {0x0F12, 0x0110}, /* #TVAR_wbt_pBaseCcms[81] */ + {0x0F12, 0x010F}, /* #TVAR_wbt_pBaseCcms[82] */ + {0x0F12, 0xFF52}, /* #TVAR_wbt_pBaseCcms[83] */ + {0x0F12, 0x01D7}, /* #TVAR_wbt_pBaseCcms[84] */ + {0x0F12, 0xFF9D}, /* #TVAR_wbt_pBaseCcms[85] */ + {0x0F12, 0x0203}, /* #TVAR_wbt_pBaseCcms[86] */ + {0x0F12, 0xFF55}, /* #TVAR_wbt_pBaseCcms[87] */ + {0x0F12, 0x0163}, /* #TVAR_wbt_pBaseCcms[88] */ + {0x0F12, 0x0126}, /* #TVAR_wbt_pBaseCcms[89] */ + {0x0F12, 0x0199}, /* #TVAR_wbt_pBaseCcms[90] D65*/ + {0x0F12, 0xFFA5}, /* #TVAR_wbt_pBaseCcms[91] */ + {0x0F12, 0xFFFC}, /* #TVAR_wbt_pBaseCcms[92] */ + {0x0F12, 0xFF6F}, /* #TVAR_wbt_pBaseCcms[93] */ + {0x0F12, 0x019F}, /* #TVAR_wbt_pBaseCcms[94] */ + {0x0F12, 0xFF43}, /* #TVAR_wbt_pBaseCcms[95] */ + {0x0F12, 0xFFFB}, /* #TVAR_wbt_pBaseCcms[96] */ + {0x0F12, 0x0003}, /* #TVAR_wbt_pBaseCcms[97] */ + {0x0F12, 0x018E}, /* #TVAR_wbt_pBaseCcms[98] */ + {0x0F12, 0x010C}, /* #TVAR_wbt_pBaseCcms[99] */ + {0x0F12, 0x010B}, /* #TVAR_wbt_pBaseCcms[100] */ + {0x0F12, 0xFF4B}, /* #TVAR_wbt_pBaseCcms[101] */ + {0x0F12, 0x01F6}, /* #TVAR_wbt_pBaseCcms[102] */ + {0x0F12, 0xFFBC}, /* #TVAR_wbt_pBaseCcms[103] */ + {0x0F12, 0x0222}, /* #TVAR_wbt_pBaseCcms[104] */ + {0x0F12, 0xFF4F}, /* #TVAR_wbt_pBaseCcms[105] */ + {0x0F12, 0x0162}, /* #TVAR_wbt_pBaseCcms[106] */ + {0x0F12, 0x0124}, /* #TVAR_wbt_pBaseCcms[107] */ + {0x002A, 0x06A0}, /* Outdoor CCM address 7000_3380 */ + {0x0F12, 0x3380}, + {0x0F12, 0x7000}, + {0x002A, 0x3380}, /* Outdoor CCM */ + {0x0F12, 0x01E0}, /* #TVAR_wbt_pOutdoorCcm[0] */ + {0x0F12, 0xFF80}, /* #TVAR_wbt_pOutdoorCcm[1] */ + {0x0F12, 0xFFD0}, /* #TVAR_wbt_pOutdoorCcm[2] */ + {0x0F12, 0xFF61}, /* #TVAR_wbt_pOutdoorCcm[3] */ + {0x0F12, 0x01BD}, /* #TVAR_wbt_pOutdoorCcm[4] */ + {0x0F12, 0xFF34}, /* #TVAR_wbt_pOutdoorCcm[5] */ + {0x0F12, 0xFFFE}, /* #TVAR_wbt_pOutdoorCcm[6] */ + {0x0F12, 0xFFF6}, /* #TVAR_wbt_pOutdoorCcm[7] */ + {0x0F12, 0x019D}, /* #TVAR_wbt_pOutdoorCcm[8] */ + {0x0F12, 0x0107}, /* #TVAR_wbt_pOutdoorCcm[9] */ + {0x0F12, 0x010F}, /* #TVAR_wbt_pOutdoorCcm[10] */ + {0x0F12, 0xFF67}, /* #TVAR_wbt_pOutdoorCcm[11] */ + {0x0F12, 0x016C}, /* #TVAR_wbt_pOutdoorCcm[12] */ + {0x0F12, 0xFF54}, /* #TVAR_wbt_pOutdoorCcm[13] */ + {0x0F12, 0x01FC}, /* #TVAR_wbt_pOutdoorCcm[14] */ + {0x0F12, 0xFF82}, /* #TVAR_wbt_pOutdoorCcm[15] */ + {0x0F12, 0x015D}, /* #TVAR_wbt_pOutdoorCcm[16] */ + {0x0F12, 0x00FD}, /* #TVAR_wbt_pOutdoorCcm[17] */ + + /* White balance */ + {0x002A, 0x0C48}, + {0x0F12, 0x03C8}, /* awbb_IndoorGrZones_m_BGrid[0] */ + {0x0F12, 0x03E2}, /* awbb_IndoorGrZones_m_BGrid[1] */ + {0x0F12, 0x038A}, /* awbb_IndoorGrZones_m_BGrid[2] */ + {0x0F12, 0x03F4}, /* awbb_IndoorGrZones_m_BGrid[3] */ + {0x0F12, 0x034E}, /* awbb_IndoorGrZones_m_BGrid[4] */ + {0x0F12, 0x03E2}, /* awbb_IndoorGrZones_m_BGrid[5] */ + {0x0F12, 0x030A}, /* awbb_IndoorGrZones_m_BGrid[6] */ + {0x0F12, 0x03B8}, /* awbb_IndoorGrZones_m_BGrid[7] */ + {0x0F12, 0x02C8}, /* awbb_IndoorGrZones_m_BGrid[8] */ + {0x0F12, 0x038A}, /* awbb_IndoorGrZones_m_BGrid[9] */ + {0x0F12, 0x029C}, /* awbb_IndoorGrZones_m_BGrid[10] */ + {0x0F12, 0x0356}, /* awbb_IndoorGrZones_m_BGrid[11] */ + {0x0F12, 0x0286}, /* awbb_IndoorGrZones_m_BGrid[12] */ + {0x0F12, 0x0322}, /* awbb_IndoorGrZones_m_BGrid[13] */ + {0x0F12, 0x026C}, /* awbb_IndoorGrZones_m_BGrid[14] */ + {0x0F12, 0x02F6}, /* awbb_IndoorGrZones_m_BGrid[15] */ + {0x0F12, 0x0254}, /* awbb_IndoorGrZones_m_BGrid[16] */ + {0x0F12, 0x02CA}, /* awbb_IndoorGrZones_m_BGrid[17] */ + {0x0F12, 0x023E}, /* awbb_IndoorGrZones_m_BGrid[18] */ + {0x0F12, 0x02B8}, /* awbb_IndoorGrZones_m_BGrid[19] */ + {0x0F12, 0x022E}, /* awbb_IndoorGrZones_m_BGrid[20] */ + {0x0F12, 0x02A4}, /* awbb_IndoorGrZones_m_BGrid[21] */ + {0x0F12, 0x0226}, /* awbb_IndoorGrZones_m_BGrid[22] */ + {0x0F12, 0x0294}, /* awbb_IndoorGrZones_m_BGrid[23] */ + {0x0F12, 0x0220}, /* awbb_IndoorGrZones_m_BGrid[24] */ + {0x0F12, 0x027E}, /* awbb_IndoorGrZones_m_BGrid[25] */ + {0x0F12, 0x022A}, /* awbb_IndoorGrZones_m_BGrid[26] */ + {0x0F12, 0x025E}, /* awbb_IndoorGrZones_m_BGrid[27] */ + {0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid[28] */ + {0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid[29] */ + {0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid[30] */ + {0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid[31] */ + {0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid[32] */ + {0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid[33] */ + {0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid[34] */ + {0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid[35] */ + {0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid[36] */ + {0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid[37] */ + {0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid[38] */ + {0x0F12, 0x0000}, /* awbb_IndoorGrZones_m_BGrid[39] */ + {0x0F12, 0x0005}, /* awbb_IndoorGrZones_m_GridStep */ + {0x002A, 0x0C9C}, + {0x0F12, 0x000E}, + {0x002A, 0x0CA0}, /* awbb_IndoorGrZones_m_Boffs */ + {0x0F12, 0x00FE}, + {0x002A, 0x0CA4}, + {0x0F12, 0x027E}, /* awbb_OutdoorGrZones_m_BGrid[0] */ + {0x0F12, 0x02AE}, /* awbb_OutdoorGrZones_m_BGrid[1] */ + {0x0F12, 0x025C}, /* awbb_OutdoorGrZones_m_BGrid[2] */ + {0x0F12, 0x02B2}, /* awbb_OutdoorGrZones_m_BGrid[3] */ + {0x0F12, 0x0244}, /* awbb_OutdoorGrZones_m_BGrid[4] */ + {0x0F12, 0x02A0}, /* awbb_OutdoorGrZones_m_BGrid[5] */ + {0x0F12, 0x0236}, /* awbb_OutdoorGrZones_m_BGrid[6] */ + {0x0F12, 0x0290}, /* awbb_OutdoorGrZones_m_BGrid[7] */ + {0x0F12, 0x0230}, /* awbb_OutdoorGrZones_m_BGrid[8] */ + {0x0F12, 0x027A}, /* awbb_OutdoorGrZones_m_BGrid[9] */ + {0x0F12, 0x0236}, /* awbb_OutdoorGrZones_m_BGrid[10] */ + {0x0F12, 0x025E}, /* awbb_OutdoorGrZones_m_BGrid[11] */ + {0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid[12] */ + {0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid[13] */ + {0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid[14] */ + {0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid[15] */ + {0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid[16] */ + {0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid[17] */ + {0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid[18] */ + {0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid[19] */ + {0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid[20] */ + {0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid[21] */ + {0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid[22] */ + {0x0F12, 0x0000}, /* awbb_OutdoorGrZones_m_BGrid[23] */ + {0x0F12, 0x0005}, + {0x002A, 0x0CD8}, /* awbb_OutdoorGrZones_m_GridStep */ + {0x0F12, 0x0006}, + {0x002A, 0x0CDC}, /* awbb_OutdoorGrZones_m_Boffs */ + {0x0F12, 0x01EE}, + + {0x002A, 0x0D88}, + {0x0F12, 0xFFAD}, /* awbb_OutdoorDetectionZone_m_BGrid[0] */ + {0x0F12, 0x005D}, /* awbb_OutdoorDetectionZone_m_BGrid[1] */ + {0x0F12, 0xFF6B}, /* awbb_OutdoorDetectionZone_m_BGrid[2] */ + {0x0F12, 0x00A0}, /* awbb_OutdoorDetectionZone_m_BGrid[3] */ + {0x0F12, 0xFEFE}, /* awbb_OutdoorDetectionZone_m_BGrid[4] */ + {0x0F12, 0x010D}, /* awbb_OutdoorDetectionZone_m_BGrid[5] */ + {0x0F12, 0xFE99}, /* awbb_OutdoorDetectionZone_m_BGrid[6] */ + {0x0F12, 0x0172}, /* awbb_OutdoorDetectionZone_m_BGrid[7] */ + {0x0F12, 0xFE6A}, /* awbb_OutdoorDetectionZone_m_BGrid[8] */ + {0x0F12, 0x01A8}, /* awbb_OutdoorDetectionZone_m_BGrid[9] */ + {0x0F12, 0x1388}, /* awbb_OutdoorDetectionZone_ZInfo_m_AbsGridStep */ + {0x0F12, 0x0000}, /* awbb_OutdoorDetectionZone_ZInfo_m_MaxNB */ + {0x0F12, 0x0005}, /* awbb_OutdoorDetectionZone_ZInfo_m_NBoffs */ + {0x0F12, 0x0000}, + {0x0F12, 0x1387}, + {0x0F12, 0x0000}, + {0x0F12, 0x1388}, + {0x0F12, 0x0000}, + + {0x002A, 0x0DA8}, + {0x0F12, 0x0913}, + {0x002A, 0x0DA4}, + {0x0F12, 0x0008}, + + {0x002A, 0x0CE0}, + {0x0F12, 0x03EA}, /* awbb_LowBrGrZones_m_BGrid[0] */ + {0x0F12, 0x044E}, /* awbb_LowBrGrZones_m_BGrid[1] */ + {0x0F12, 0x035E}, /* awbb_LowBrGrZones_m_BGrid[2] */ + {0x0F12, 0x044C}, /* awbb_LowBrGrZones_m_BGrid[3] */ + {0x0F12, 0x02FA}, /* awbb_LowBrGrZones_m_BGrid[4] */ + {0x0F12, 0x0434}, /* awbb_LowBrGrZones_m_BGrid[5] */ + {0x0F12, 0x02AA}, /* awbb_LowBrGrZones_m_BGrid[6] */ + {0x0F12, 0x03F2}, /* awbb_LowBrGrZones_m_BGrid[7] */ + {0x0F12, 0x0266}, /* awbb_LowBrGrZones_m_BGrid[8] */ + {0x0F12, 0x03AE}, /* awbb_LowBrGrZones_m_BGrid[9] */ + {0x0F12, 0x022C}, /* awbb_L0CA4owBrGrZones_m_BGrid[10] */ + {0x0F12, 0x035A}, /* awbb_LowBrGrZones_m_BGrid[11] */ + {0x0F12, 0x020E}, /* awbb_LowBrGrZones_m_BGrid[12] */ + {0x0F12, 0x0314}, /* awbb_LowBrGrZones_m_BGrid[13] */ + {0x0F12, 0x01F4}, /* awbb_LowBrGrZones_m_BGrid[14] */ + {0x0F12, 0x02E0}, /* awbb_LowBrGrZones_m_BGrid[15] */ + {0x0F12, 0x01E2}, /* awbb_LowBrGrZones_m_BGrid[16] */ + {0x0F12, 0x02AA}, /* awbb_LowBrGrZones_m_BGrid[17] */ + {0x0F12, 0x01E6}, /* awbb_LowBrGrZones_m_BGrid[18] */ + {0x0F12, 0x0264}, /* awbb_LowBrGrZones_m_BGrid[19] */ + {0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid[20] */ + {0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid[21] */ + {0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid[22] */ + {0x0F12, 0x0000}, /* awbb_LowBrGrZones_m_BGrid[23] */ + {0x0F12, 0x0006}, /* awbb_LowBrGrZones_m_GridStep */ + {0x002A, 0x0D14}, + {0x0F12, 0x000A}, + {0x002A, 0x0D18}, /* awbb_LowBrGrZones_m_Boffs */ + {0x0F12, 0x009A}, + {0x002A, 0x0D1C}, + {0x0F12, 0x036C}, /* awbb_CrclLowT_R_c */ + {0x002A, 0x0D20}, + {0x0F12, 0x011C}, /* awbb_CrclLowT_B_c */ + {0x002A, 0x0D24}, + {0x0F12, 0x6184}, /* awbb_CrclLowT_Rad_c */ + {0x002A, 0x0D2C}, + {0x0F12, 0x0135}, /* awbb_IntcR */ + {0x0F12, 0x012B}, /* awbb_IntcB */ + {0x002A, 0x0D28}, + {0x0F12, 0x024E}, + {0x0F12, 0x027B}, + {0x002A, 0x0E4C}, + {0x0F12, 0x0000}, + {0x002A, 0x0D4C}, + {0x0F12, 0x0653}, + {0x0F12, 0x02EB}, + {0x0F12, 0x002C}, + {0x0F12, 0x000B}, + {0x002A, 0x0D5C}, /* awbb_LowTempRB */ + {0x0F12, 0x7FFF}, + {0x0F12, 0x0050}, + {0x002A, 0x0D46}, + {0x0F12, 0x053A}, /* awbb_MvEq_RBthresh */ + {0x002A, 0x0D4A}, + {0x0F12, 0x000A}, + {0x002A, 0x0DD4}, + {0x0F12, 0xFFFE}, + {0x0F12, 0xFFEC}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0xFFFD}, + {0x0F12, 0xFFEC}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0xFFFC}, + {0x0F12, 0xFFEC}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + + {0x0F12, 0x0000}, + {0x0F12, 0x0028}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0028}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0028}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + + {0x0F12, 0x02F0}, + {0x0F12, 0x0358}, + {0x0F12, 0x03A5}, + {0x0F12, 0x0F9C}, + {0x0F12, 0x0FFA}, + {0x0F12, 0x10B5}, + {0x0F12, 0x1126}, + {0x0F12, 0x1176}, + {0x0F12, 0x1220}, + {0x0F12, 0x00B2}, + {0x0F12, 0x00B8}, + {0x0F12, 0x00B7}, + {0x0F12, 0x00B3}, + {0x002A, 0x0E3E}, + {0x0F12, 0x0000}, + {0x002A, 0x22DE}, + {0x0F12, 0x0004}, + {0x002A, 0x337C}, + {0x0F12, 0x00B3}, + {0x0F12, 0x0040}, + {0x002A, 0x0E44}, + {0x0F12, 0x053C}, + {0x0F12, 0x0400}, + {0x0F12, 0x055C}, + {0x002A, 0x0E36}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + + {0x002A, 0x0E4A}, /* Grid offset enable */ + {0x0F12, 0x0001}, + + /* Set GAMMA */ + {0x002A, 0x3288}, + {0x0F12, 0x0000}, /* #SARR_usDualGammaLutRGBIndoor_0__0_ 0x70003288 */ + {0x0F12, 0x0004}, /* #SARR_usDualGammaLutRGBIndoor_0__1_ 0x7000328A */ + {0x0F12, 0x0010}, /* #SARR_usDualGammaLutRGBIndoor_0__2_ 0x7000328C */ + {0x0F12, 0x002A}, /* #SARR_usDualGammaLutRGBIndoor_0__3_ 0x7000328E */ + {0x0F12, 0x0062}, /* #SARR_usDualGammaLutRGBIndoor_0__4_ 0x70003290 */ + {0x0F12, 0x00D5}, /* #SARR_usDualGammaLutRGBIndoor_0__5_ 0x70003292 */ + {0x0F12, 0x0138}, /* #SARR_usDualGammaLutRGBIndoor_0__6_ 0x70003294 */ + {0x0F12, 0x0161}, /* #SARR_usDualGammaLutRGBIndoor_0__7_ 0x70003296 */ + {0x0F12, 0x0186}, /* #SARR_usDualGammaLutRGBIndoor_0__8_ 0x70003298 */ + {0x0F12, 0x01BC}, /* #SARR_usDualGammaLutRGBIndoor_0__9_ 0x7000329A */ + {0x0F12, 0x01E8}, /* #SARR_usDualGammaLutRGBIndoor_0__10_ 0x7000329C */ + {0x0F12, 0x020F}, /* #SARR_usDualGammaLutRGBIndoor_0__11_ 0x7000329E */ + {0x0F12, 0x0232}, /* #SARR_usDualGammaLutRGBIndoor_0__12_ 0x700032A0 */ + {0x0F12, 0x0273}, /* #SARR_usDualGammaLutRGBIndoor_0__13_ 0x700032A2 */ + {0x0F12, 0x02AF}, /* #SARR_usDualGammaLutRGBIndoor_0__14_ 0x700032A4 */ + {0x0F12, 0x0309}, /* #SARR_usDualGammaLutRGBIndoor_0__15_ 0x700032A6 */ + {0x0F12, 0x0355}, /* #SARR_usDualGammaLutRGBIndoor_0__16_ 0x700032A8 */ + {0x0F12, 0x0394}, /* #SARR_usDualGammaLutRGBIndoor_0__17_ 0x700032AA */ + {0x0F12, 0x03CE}, /* #SARR_usDualGammaLutRGBIndoor_0__18_ 0x700032AC */ + {0x0F12, 0x03FF}, /* #SARR_usDualGammaLutRGBIndoor_0__19_ 0x700032AE */ + {0x0F12, 0x0000}, /* #SARR_usDualGammaLutRGBIndoor_1__0_ 0x700032B0 */ + {0x0F12, 0x0004}, /* #SARR_usDualGammaLutRGBIndoor_1__1_ 0x700032B2 */ + {0x0F12, 0x0010}, /* #SARR_usDualGammaLutRGBIndoor_1__2_ 0x700032B4 */ + {0x0F12, 0x002A}, /* #SARR_usDualGammaLutRGBIndoor_1__3_ 0x700032B6 */ + {0x0F12, 0x0062}, /* #SARR_usDualGammaLutRGBIndoor_1__4_ 0x700032B8 */ + {0x0F12, 0x00D5}, /* #SARR_usDualGammaLutRGBIndoor_1__5_ 0x700032BA */ + {0x0F12, 0x0138}, /* #SARR_usDualGammaLutRGBIndoor_1__6_ 0x700032BC */ + {0x0F12, 0x0161}, /* #SARR_usDualGammaLutRGBIndoor_1__7_ 0x700032BE */ + {0x0F12, 0x0186}, /* #SARR_usDualGammaLutRGBIndoor_1__8_ 0x700032C0 */ + {0x0F12, 0x01BC}, /* #SARR_usDualGammaLutRGBIndoor_1__9_ 0x700032C2 */ + {0x0F12, 0x01E8}, /* #SARR_usDualGammaLutRGBIndoor_1__10_ 0x700032C4 */ + {0x0F12, 0x020F}, /* #SARR_usDualGammaLutRGBIndoor_1__11_ 0x700032C6 */ + {0x0F12, 0x0232}, /* #SARR_usDualGammaLutRGBIndoor_1__12_ 0x700032C8 */ + {0x0F12, 0x0273}, /* #SARR_usDualGammaLutRGBIndoor_1__13_ 0x700032CA */ + {0x0F12, 0x02AF}, /* #SARR_usDualGammaLutRGBIndoor_1__14_ 0x700032CC */ + {0x0F12, 0x0309}, /* #SARR_usDualGammaLutRGBIndoor_1__15_ 0x700032CE */ + {0x0F12, 0x0355}, /* #SARR_usDualGammaLutRGBIndoor_1__16_ 0x700032D0 */ + {0x0F12, 0x0394}, /* #SARR_usDualGammaLutRGBIndoor_1__17_ 0x700032D2 */ + {0x0F12, 0x03CE}, /* #SARR_usDualGammaLutRGBIndoor_1__18_ 0x700032D4 */ + {0x0F12, 0x03FF}, /* #SARR_usDualGammaLutRGBIndoor_1__19_ 0x700032D6 */ + {0x0F12, 0x0000}, /* #SARR_usDualGammaLutRGBIndoor_2__0_ 0x700032D8 */ + {0x0F12, 0x0004}, /* #SARR_usDualGammaLutRGBIndoor_2__1_ 0x700032DA */ + {0x0F12, 0x0010}, /* #SARR_usDualGammaLutRGBIndoor_2__2_ 0x700032DC */ + {0x0F12, 0x002A}, /* #SARR_usDualGammaLutRGBIndoor_2__3_ 0x700032DE */ + {0x0F12, 0x0062}, /* #SARR_usDualGammaLutRGBIndoor_2__4_ 0x700032E0 */ + {0x0F12, 0x00D5}, /* #SARR_usDualGammaLutRGBIndoor_2__5_ 0x700032E2 */ + {0x0F12, 0x0138}, /* #SARR_usDualGammaLutRGBIndoor_2__6_ 0x700032E4 */ + {0x0F12, 0x0161}, /* #SARR_usDualGammaLutRGBIndoor_2__7_ 0x700032E6 */ + {0x0F12, 0x0186}, /* #SARR_usDualGammaLutRGBIndoor_2__8_ 0x700032E8 */ + {0x0F12, 0x01BC}, /* #SARR_usDualGammaLutRGBIndoor_2__9_ 0x700032EA */ + {0x0F12, 0x01E8}, /* #SARR_usDualGammaLutRGBIndoor_2__10_ 0x700032EC */ + {0x0F12, 0x020F}, /* #SARR_usDualGammaLutRGBIndoor_2__11_ 0x700032EE */ + {0x0F12, 0x0232}, /* #SARR_usDualGammaLutRGBIndoor_2__12_ 0x700032F0 */ + {0x0F12, 0x0273}, /* #SARR_usDualGammaLutRGBIndoor_2__13_ 0x700032F2 */ + {0x0F12, 0x02AF}, /* #SARR_usDualGammaLutRGBIndoor_2__14_ 0x700032F4 */ + {0x0F12, 0x0309}, /* #SARR_usDualGammaLutRGBIndoor_2__15_ 0x700032F6 */ + {0x0F12, 0x0355}, /* #SARR_usDualGammaLutRGBIndoor_2__16_ 0x700032F8 */ + {0x0F12, 0x0394}, /* #SARR_usDualGammaLutRGBIndoor_2__17_ 0x700032FA */ + {0x0F12, 0x03CE}, /* #SARR_usDualGammaLutRGBIndoor_2__18_ 0x700032FC */ + {0x0F12, 0x03FF}, /* #SARR_usDualGammaLutRGBIndoor_2__19_ 0x700032FE */ + {0x0F12, 0x0000}, /* #SARR_usDualGammaLutRGBOutdoor_0__0_ 0x70003300 */ + {0x0F12, 0x0004}, /* #SARR_usDualGammaLutRGBOutdoor_0__1_ 0x70003302 */ + {0x0F12, 0x0010}, /* #SARR_usDualGammaLutRGBOutdoor_0__2_ 0x70003304 */ + {0x0F12, 0x002A}, /* #SARR_usDualGammaLutRGBOutdoor_0__3_ 0x70003306 */ + {0x0F12, 0x0062}, /* #SARR_usDualGammaLutRGBOutdoor_0__4_ 0x70003308 */ + {0x0F12, 0x00D5}, /* #SARR_usDualGammaLutRGBOutdoor_0__5_ 0x7000330A */ + {0x0F12, 0x0138}, /* #SARR_usDualGammaLutRGBOutdoor_0__6_ 0x7000330C */ + {0x0F12, 0x0161}, /* #SARR_usDualGammaLutRGBOutdoor_0__7_ 0x7000330E */ + {0x0F12, 0x0186}, /* #SARR_usDualGammaLutRGBOutdoor_0__8_ 0x70003310 */ + {0x0F12, 0x01BC}, /* #SARR_usDualGammaLutRGBOutdoor_0__9_ 0x70003312 */ + {0x0F12, 0x01E8}, /* #SARR_usDualGammaLutRGBOutdoor_0__10_0x70003314 */ + {0x0F12, 0x020F}, /* #SARR_usDualGammaLutRGBOutdoor_0__11_0x70003316 */ + {0x0F12, 0x0232}, /* #SARR_usDualGammaLutRGBOutdoor_0__12_0x70003318 */ + {0x0F12, 0x0273}, /* #SARR_usDualGammaLutRGBOutdoor_0__13_0x7000331A */ + {0x0F12, 0x02AF}, /* #SARR_usDualGammaLutRGBOutdoor_0__14_0x7000331C */ + {0x0F12, 0x0309}, /* #SARR_usDualGammaLutRGBOutdoor_0__15_0x7000331E */ + {0x0F12, 0x0355}, /* #SARR_usDualGammaLutRGBOutdoor_0__16_0x70003320 */ + {0x0F12, 0x0394}, /* #SARR_usDualGammaLutRGBOutdoor_0__17_0x70003322 */ + {0x0F12, 0x03CE}, /* #SARR_usDualGammaLutRGBOutdoor_0__18_0x70003324 */ + {0x0F12, 0x03FF}, /* #SARR_usDualGammaLutRGBOutdoor_0__19_0x70003326 */ + {0x0F12, 0x0000}, /* #SARR_usDualGammaLutRGBOutdoor_1__0_ 0x70003328 */ + {0x0F12, 0x0004}, /* #SARR_usDualGammaLutRGBOutdoor_1__1_ 0x7000332A */ + {0x0F12, 0x0010}, /* #SARR_usDualGammaLutRGBOutdoor_1__2_ 0x7000332C */ + {0x0F12, 0x002A}, /* #SARR_usDualGammaLutRGBOutdoor_1__3_ 0x7000332E */ + {0x0F12, 0x0062}, /* #SARR_usDualGammaLutRGBOutdoor_1__4_ 0x70003330 */ + {0x0F12, 0x00D5}, /* #SARR_usDualGammaLutRGBOutdoor_1__5_ 0x70003332 */ + {0x0F12, 0x0138}, /* #SARR_usDualGammaLutRGBOutdoor_1__6_ 0x70003334 */ + {0x0F12, 0x0161}, /* #SARR_usDualGammaLutRGBOutdoor_1__7_ 0x70003336 */ + {0x0F12, 0x0186}, /* #SARR_usDualGammaLutRGBOutdoor_1__8_ 0x70003338 */ + {0x0F12, 0x01BC}, /* #SARR_usDualGammaLutRGBOutdoor_1__9_ 0x7000333A */ + {0x0F12, 0x01E8}, /* #SARR_usDualGammaLutRGBOutdoor_1__10_0x7000333C */ + {0x0F12, 0x020F}, /* #SARR_usDualGammaLutRGBOutdoor_1__11_0x7000333E */ + {0x0F12, 0x0232}, /* #SARR_usDualGammaLutRGBOutdoor_1__12_0x70003340 */ + {0x0F12, 0x0273}, /* #SARR_usDualGammaLutRGBOutdoor_1__13_0x70003342 */ + {0x0F12, 0x02AF}, /* #SARR_usDualGammaLutRGBOutdoor_1__14_0x70003344 */ + {0x0F12, 0x0309}, /* #SARR_usDualGammaLutRGBOutdoor_1__15_0x70003346 */ + {0x0F12, 0x0355}, /* #SARR_usDualGammaLutRGBOutdoor_1__16_0x70003348 */ + {0x0F12, 0x0394}, /* #SARR_usDualGammaLutRGBOutdoor_1__17_0x7000334A */ + {0x0F12, 0x03CE}, /* #SARR_usDualGammaLutRGBOutdoor_1__18_0x7000334C */ + {0x0F12, 0x03FF}, /* #SARR_usDualGammaLutRGBOutdoor_1__19_0x7000334E */ + {0x0F12, 0x0000}, /* #SARR_usDualGammaLutRGBOutdoor_2__0_ 0x70003350 */ + {0x0F12, 0x0004}, /* #SARR_usDualGammaLutRGBOutdoor_2__1_ 0x70003352 */ + {0x0F12, 0x0010}, /* #SARR_usDualGammaLutRGBOutdoor_2__2_ 0x70003354 */ + {0x0F12, 0x002A}, /* #SARR_usDualGammaLutRGBOutdoor_2__3_ 0x70003356 */ + {0x0F12, 0x0062}, /* #SARR_usDualGammaLutRGBOutdoor_2__4_ 0x70003358 */ + {0x0F12, 0x00D5}, /* #SARR_usDualGammaLutRGBOutdoor_2__5_ 0x7000335A */ + {0x0F12, 0x0138}, /* #SARR_usDualGammaLutRGBOutdoor_2__6_ 0x7000335C */ + {0x0F12, 0x0161}, /* #SARR_usDualGammaLutRGBOutdoor_2__7_ 0x7000335E */ + {0x0F12, 0x0186}, /* #SARR_usDualGammaLutRGBOutdoor_2__8_ 0x70003360 */ + {0x0F12, 0x01BC}, /* #SARR_usDualGammaLutRGBOutdoor_2__9_ 0x70003362 */ + {0x0F12, 0x01E8}, /* #SARR_usDualGammaLutRGBOutdoor_2__10_0x70003364 */ + {0x0F12, 0x020F}, /* #SARR_usDualGammaLutRGBOutdoor_2__11_0x70003366 */ + {0x0F12, 0x0232}, /* #SARR_usDualGammaLutRGBOutdoor_2__12_0x70003368 */ + {0x0F12, 0x0273}, /* #SARR_usDualGammaLutRGBOutdoor_2__13_0x7000336A */ + {0x0F12, 0x02AF}, /* #SARR_usDualGammaLutRGBOutdoor_2__14_0x7000336C */ + {0x0F12, 0x0309}, /* #SARR_usDualGammaLutRGBOutdoor_2__15_0x7000336E */ + {0x0F12, 0x0355}, /* #SARR_usDualGammaLutRGBOutdoor_2__16_0x70003370 */ + {0x0F12, 0x0394}, /* #SARR_usDualGammaLutRGBOutdoor_2__17_0x70003372 */ + {0x0F12, 0x03CE}, /* #SARR_usDualGammaLutRGBOutdoor_2__18_0x70003374 */ + {0x0F12, 0x03FF}, /* #SARR_usDualGammaLutRGBOutdoor_2__19_0x70003376 */ + + {0x002A, 0x06A6}, + {0x0F12, 0x00CA}, /* #SARR_AwbCcmCord_0_ */ + {0x0F12, 0x00EA}, /* #SARR_AwbCcmCord_1_ */ + {0x0F12, 0x0110}, /* #SARR_AwbCcmCord_2_ */ + {0x0F12, 0x0124}, /* #SARR_AwbCcmCord_3_ */ + {0x0F12, 0x0160}, /* #SARR_AwbCcmCord_4_ */ + {0x0F12, 0x0180}, /* #SARR_AwbCcmCord_5_ */ + + /* Set AFIT */ + /* Noise index */ + {0x002A, 0x0764}, + {0x0F12, 0x0041}, /* #afit_uNoiseIndInDoor[0] */ + {0x0F12, 0x0063}, /* #afit_uNoiseIndInDoor[1] */ + {0x0F12, 0x00BB}, /* #afit_uNoiseIndInDoor[2] */ + {0x0F12, 0x0193}, /* #afit_uNoiseIndInDoor[3] */ + {0x0F12, 0x02BC}, /* #afit_uNoiseIndInDoor[4] */ + + /* AFIT table start address 7000_07C4 */ + {0x002A, 0x0770}, + {0x0F12, 0x07C4}, + {0x0F12, 0x7000}, + + /* AFIT table (Variables) */ + {0x002A, 0x07C4}, + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[0] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[1] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[2] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[3] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[4] */ + {0x0F12, 0x00C4}, /* #TVAR_afit_pBaseVals[5] */ + {0x0F12, 0x03FF}, /* #TVAR_afit_pBaseVals[6] */ + {0x0F12, 0x009C}, /* #TVAR_afit_pBaseVals[7] */ + {0x0F12, 0x017C}, /* #TVAR_afit_pBaseVals[8] */ + {0x0F12, 0x03FF}, /* #TVAR_afit_pBaseVals[9] */ + {0x0F12, 0x000C}, /* #TVAR_afit_pBaseVals[10] */ + {0x0F12, 0x0010}, /* #TVAR_afit_pBaseVals[11] */ + {0x0F12, 0x0104}, /* #TVAR_afit_pBaseVals[12] */ + {0x0F12, 0x03E8}, /* #TVAR_afit_pBaseVals[13] */ + {0x0F12, 0x0023}, /* #TVAR_afit_pBaseVals[14] */ + {0x0F12, 0x012C}, /* #TVAR_afit_pBaseVals[15] */ + {0x0F12, 0x0070}, /* #TVAR_afit_pBaseVals[16] */ + {0x0F12, 0x0010}, /* #TVAR_afit_pBaseVals[17] */ + {0x0F12, 0x0010}, /* #TVAR_afit_pBaseVals[18] */ + {0x0F12, 0x01AA}, /* #TVAR_afit_pBaseVals[19] */ + {0x0F12, 0x0064}, /* #TVAR_afit_pBaseVals[20] */ + {0x0F12, 0x0064}, /* #TVAR_afit_pBaseVals[21] */ + {0x0F12, 0x000A}, /* #TVAR_afit_pBaseVals[22] */ + {0x0F12, 0x000A}, /* #TVAR_afit_pBaseVals[23] */ + {0x0F12, 0x003C}, /* #TVAR_afit_pBaseVals[24] */ + {0x0F12, 0x0024}, /* #TVAR_afit_pBaseVals[25] */ + {0x0F12, 0x002A}, /* #TVAR_afit_pBaseVals[26] */ + {0x0F12, 0x0024}, /* #TVAR_afit_pBaseVals[27] */ + {0x0F12, 0x002A}, /* #TVAR_afit_pBaseVals[28] */ + {0x0F12, 0x0024}, /* #TVAR_afit_pBaseVals[29] */ + {0x0F12, 0x0A24}, /* #TVAR_afit_pBaseVals[30] */ + {0x0F12, 0x1701}, /* #TVAR_afit_pBaseVals[31] */ + {0x0F12, 0x0229}, /* #TVAR_afit_pBaseVals[32] */ + {0x0F12, 0x1403}, /* #TVAR_afit_pBaseVals[33] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[34] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[35] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[36] */ + {0x0F12, 0x00FF}, /* #TVAR_afit_pBaseVals[37] */ + {0x0F12, 0x043B}, /* #TVAR_afit_pBaseVals[38] */ + {0x0F12, 0x1414}, /* #TVAR_afit_pBaseVals[39] */ + {0x0F12, 0x0301}, /* #TVAR_afit_pBaseVals[40] */ + {0x0F12, 0xFF07}, /* #TVAR_afit_pBaseVals[41] */ + {0x0F12, 0x051E}, /* #TVAR_afit_pBaseVals[42] */ + {0x0F12, 0x0A1E}, /* #TVAR_afit_pBaseVals[43] */ + {0x0F12, 0x0F0F}, /* #TVAR_afit_pBaseVals[44] */ + {0x0F12, 0x0A05}, /* #TVAR_afit_pBaseVals[45] */ + {0x0F12, 0x0A3C}, /* #TVAR_afit_pBaseVals[46] */ + {0x0F12, 0x0A28}, /* #TVAR_afit_pBaseVals[47] */ + {0x0F12, 0x0002}, /* #TVAR_afit_pBaseVals[48] */ + {0x0F12, 0x00FF}, /* #TVAR_afit_pBaseVals[49] */ + {0x0F12, 0x1002}, /* #TVAR_afit_pBaseVals[50] */ + {0x0F12, 0x001D}, /* #TVAR_afit_pBaseVals[51] */ + {0x0F12, 0x0900}, /* #TVAR_afit_pBaseVals[52] */ + {0x0F12, 0x0600}, /* #TVAR_afit_pBaseVals[53] */ + {0x0F12, 0x0504}, /* #TVAR_afit_pBaseVals[54] */ + {0x0F12, 0x0305}, /* #TVAR_afit_pBaseVals[55] */ + {0x0F12, 0x5003}, /* #TVAR_afit_pBaseVals[56] */ + {0x0F12, 0x006E}, /* #TVAR_afit_pBaseVals[57] */ + {0x0F12, 0x0078}, /* #TVAR_afit_pBaseVals[58] */ + {0x0F12, 0x0080}, /* #TVAR_afit_pBaseVals[59] */ + {0x0F12, 0x1414}, /* #TVAR_afit_pBaseVals[60] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[61] */ + {0x0F12, 0x5002}, /* #TVAR_afit_pBaseVals[62] */ + {0x0F12, 0x7850}, /* #TVAR_afit_pBaseVals[63] */ + {0x0F12, 0x2878}, /* #TVAR_afit_pBaseVals[64] */ + {0x0F12, 0x0A00}, /* #TVAR_afit_pBaseVals[65] */ + {0x0F12, 0x1403}, /* #TVAR_afit_pBaseVals[66] */ + {0x0F12, 0x1E0C}, /* #TVAR_afit_pBaseVals[67] */ + {0x0F12, 0x070A}, /* #TVAR_afit_pBaseVals[68] */ + {0x0F12, 0x32FF}, /* #TVAR_afit_pBaseVals[69] */ + {0x0F12, 0x5004}, /* #TVAR_afit_pBaseVals[70] */ + {0x0F12, 0x0F40}, /* #TVAR_afit_pBaseVals[71] */ + {0x0F12, 0x400F}, /* #TVAR_afit_pBaseVals[72] */ + {0x0F12, 0x0204}, /* #TVAR_afit_pBaseVals[73] */ + {0x0F12, 0x1E03}, /* #TVAR_afit_pBaseVals[74] */ + {0x0F12, 0x011E}, /* #TVAR_afit_pBaseVals[75] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[76] */ + {0x0F12, 0x5050}, /* #TVAR_afit_pBaseVals[77] */ + {0x0F12, 0x7878}, /* #TVAR_afit_pBaseVals[78] */ + {0x0F12, 0x0028}, /* #TVAR_afit_pBaseVals[79] */ + {0x0F12, 0x030A}, /* #TVAR_afit_pBaseVals[80] */ + {0x0F12, 0x0714}, /* #TVAR_afit_pBaseVals[81] */ + {0x0F12, 0x0A1E}, /* #TVAR_afit_pBaseVals[82] */ + {0x0F12, 0xFF07}, /* #TVAR_afit_pBaseVals[83] */ + {0x0F12, 0x0432}, /* #TVAR_afit_pBaseVals[84] */ + {0x0F12, 0x4050}, /* #TVAR_afit_pBaseVals[85] */ + {0x0F12, 0x0F0F}, /* #TVAR_afit_pBaseVals[86] */ + {0x0F12, 0x0440}, /* #TVAR_afit_pBaseVals[87] */ + {0x0F12, 0x0302}, /* #TVAR_afit_pBaseVals[88] */ + {0x0F12, 0x1E1E}, /* #TVAR_afit_pBaseVals[89] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[90] */ + {0x0F12, 0x5001}, /* #TVAR_afit_pBaseVals[91] */ + {0x0F12, 0x7850}, /* #TVAR_afit_pBaseVals[92] */ + {0x0F12, 0x2878}, /* #TVAR_afit_pBaseVals[93] */ + {0x0F12, 0x0A00}, /* #TVAR_afit_pBaseVals[94] */ + {0x0F12, 0x1403}, /* #TVAR_afit_pBaseVals[95] */ + {0x0F12, 0x1E07}, /* #TVAR_afit_pBaseVals[96] */ + {0x0F12, 0x070A}, /* #TVAR_afit_pBaseVals[97] */ + {0x0F12, 0x32FF}, /* #TVAR_afit_pBaseVals[98] */ + {0x0F12, 0x5004}, /* #TVAR_afit_pBaseVals[99] */ + {0x0F12, 0x0F40}, /* #TVAR_afit_pBaseVals[100] */ + {0x0F12, 0x400F}, /* #TVAR_afit_pBaseVals[101] */ + {0x0F12, 0x0204}, /* #TVAR_afit_pBaseVals[102] */ + {0x0F12, 0x0003}, /* #TVAR_afit_pBaseVals[103] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[104] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[105] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[106] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[107] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[108] */ + {0x0F12, 0x00C4}, /* #TVAR_afit_pBaseVals[109] */ + {0x0F12, 0x03FF}, /* #TVAR_afit_pBaseVals[110] */ + {0x0F12, 0x009C}, /* #TVAR_afit_pBaseVals[111] */ + {0x0F12, 0x017C}, /* #TVAR_afit_pBaseVals[112] */ + {0x0F12, 0x03FF}, /* #TVAR_afit_pBaseVals[113] */ + {0x0F12, 0x000C}, /* #TVAR_afit_pBaseVals[114] */ + {0x0F12, 0x0010}, /* #TVAR_afit_pBaseVals[115] */ + {0x0F12, 0x0104}, /* #TVAR_afit_pBaseVals[116] */ + {0x0F12, 0x03E8}, /* #TVAR_afit_pBaseVals[117] */ + {0x0F12, 0x0023}, /* #TVAR_afit_pBaseVals[118] */ + {0x0F12, 0x012C}, /* #TVAR_afit_pBaseVals[119] */ + {0x0F12, 0x0070}, /* #TVAR_afit_pBaseVals[120] */ + {0x0F12, 0x0008}, /* #TVAR_afit_pBaseVals[121] */ + {0x0F12, 0x0008}, /* #TVAR_afit_pBaseVals[122] */ + {0x0F12, 0x01AA}, /* #TVAR_afit_pBaseVals[123] */ + {0x0F12, 0x003C}, /* #TVAR_afit_pBaseVals[124] */ + {0x0F12, 0x003C}, /* #TVAR_afit_pBaseVals[125] */ + {0x0F12, 0x0005}, /* #TVAR_afit_pBaseVals[126] */ + {0x0F12, 0x0005}, /* #TVAR_afit_pBaseVals[127] */ + {0x0F12, 0x0050}, /* #TVAR_afit_pBaseVals[128] */ + {0x0F12, 0x0024}, /* #TVAR_afit_pBaseVals[129] */ + {0x0F12, 0x002A}, /* #TVAR_afit_pBaseVals[130] */ + {0x0F12, 0x0024}, /* #TVAR_afit_pBaseVals[131] */ + {0x0F12, 0x002A}, /* #TVAR_afit_pBaseVals[132] */ + {0x0F12, 0x0024}, /* #TVAR_afit_pBaseVals[133] */ + {0x0F12, 0x0A24}, /* #TVAR_afit_pBaseVals[134] */ + {0x0F12, 0x1701}, /* #TVAR_afit_pBaseVals[135] */ + {0x0F12, 0x0229}, /* #TVAR_afit_pBaseVals[136] */ + {0x0F12, 0x1403}, /* #TVAR_afit_pBaseVals[137] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[138] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[139] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[140] */ + {0x0F12, 0x00FF}, /* #TVAR_afit_pBaseVals[141] */ + {0x0F12, 0x043B}, /* #TVAR_afit_pBaseVals[142] */ + {0x0F12, 0x1414}, /* #TVAR_afit_pBaseVals[143] */ + {0x0F12, 0x0301}, /* #TVAR_afit_pBaseVals[144] */ + {0x0F12, 0xFF07}, /* #TVAR_afit_pBaseVals[145] */ + {0x0F12, 0x051E}, /* #TVAR_afit_pBaseVals[146] */ + {0x0F12, 0x0A1E}, /* #TVAR_afit_pBaseVals[147] */ + {0x0F12, 0x0F0F}, /* #TVAR_afit_pBaseVals[148] */ + {0x0F12, 0x0A03}, /* #TVAR_afit_pBaseVals[149] */ + {0x0F12, 0x0A3C}, /* #TVAR_afit_pBaseVals[150] */ + {0x0F12, 0x0A28}, /* #TVAR_afit_pBaseVals[151] */ + {0x0F12, 0x0002}, /* #TVAR_afit_pBaseVals[152] */ + {0x0F12, 0x00FF}, /* #TVAR_afit_pBaseVals[153] */ + {0x0F12, 0x1102}, /* #TVAR_afit_pBaseVals[154] */ + {0x0F12, 0x001D}, /* #TVAR_afit_pBaseVals[155] */ + {0x0F12, 0x0900}, /* #TVAR_afit_pBaseVals[156] */ + {0x0F12, 0x0600}, /* #TVAR_afit_pBaseVals[157] */ + {0x0F12, 0x0504}, /* #TVAR_afit_pBaseVals[158] */ + {0x0F12, 0x0305}, /* #TVAR_afit_pBaseVals[159] */ + {0x0F12, 0x6403}, /* #TVAR_afit_pBaseVals[160] */ + {0x0F12, 0x0080}, /* #TVAR_afit_pBaseVals[161] */ + {0x0F12, 0x0080}, /* #TVAR_afit_pBaseVals[162] */ + {0x0F12, 0x0080}, /* #TVAR_afit_pBaseVals[163] */ + {0x0F12, 0x1919}, /* #TVAR_afit_pBaseVals[164] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[165] */ + {0x0F12, 0x3C02}, /* #TVAR_afit_pBaseVals[166] */ + {0x0F12, 0x553C}, /* #TVAR_afit_pBaseVals[167] */ + {0x0F12, 0x2855}, /* #TVAR_afit_pBaseVals[168] */ + {0x0F12, 0x0A00}, /* #TVAR_afit_pBaseVals[169] */ + {0x0F12, 0x1403}, /* #TVAR_afit_pBaseVals[170] */ + {0x0F12, 0x1E0C}, /* #TVAR_afit_pBaseVals[171] */ + {0x0F12, 0x070A}, /* #TVAR_afit_pBaseVals[172] */ + {0x0F12, 0x32FF}, /* #TVAR_afit_pBaseVals[173] */ + {0x0F12, 0x5004}, /* #TVAR_afit_pBaseVals[174] */ + {0x0F12, 0x0F40}, /* #TVAR_afit_pBaseVals[175] */ + {0x0F12, 0x400F}, /* #TVAR_afit_pBaseVals[176] */ + {0x0F12, 0x0204}, /* #TVAR_afit_pBaseVals[177] */ + {0x0F12, 0x1E03}, /* #TVAR_afit_pBaseVals[178] */ + {0x0F12, 0x011E}, /* #TVAR_afit_pBaseVals[179] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[180] */ + {0x0F12, 0x3232}, /* #TVAR_afit_pBaseVals[181] */ + {0x0F12, 0x3C3C}, /* #TVAR_afit_pBaseVals[182] */ + {0x0F12, 0x0028}, /* #TVAR_afit_pBaseVals[183] */ + {0x0F12, 0x030A}, /* #TVAR_afit_pBaseVals[184] */ + {0x0F12, 0x0714}, /* #TVAR_afit_pBaseVals[185] */ + {0x0F12, 0x0A1E}, /* #TVAR_afit_pBaseVals[186] */ + {0x0F12, 0xFF07}, /* #TVAR_afit_pBaseVals[187] */ + {0x0F12, 0x0432}, /* #TVAR_afit_pBaseVals[188] */ + {0x0F12, 0x4050}, /* #TVAR_afit_pBaseVals[189] */ + {0x0F12, 0x0F0F}, /* #TVAR_afit_pBaseVals[190] */ + {0x0F12, 0x0440}, /* #TVAR_afit_pBaseVals[191] */ + {0x0F12, 0x0302}, /* #TVAR_afit_pBaseVals[192] */ + {0x0F12, 0x1E1E}, /* #TVAR_afit_pBaseVals[193] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[194] */ + {0x0F12, 0x3201}, /* #TVAR_afit_pBaseVals[195] */ + {0x0F12, 0x3C32}, /* #TVAR_afit_pBaseVals[196] */ + {0x0F12, 0x283C}, /* #TVAR_afit_pBaseVals[197] */ + {0x0F12, 0x0A00}, /* #TVAR_afit_pBaseVals[198] */ + {0x0F12, 0x1403}, /* #TVAR_afit_pBaseVals[199] */ + {0x0F12, 0x1E07}, /* #TVAR_afit_pBaseVals[200] */ + {0x0F12, 0x070A}, /* #TVAR_afit_pBaseVals[201] */ + {0x0F12, 0x32FF}, /* #TVAR_afit_pBaseVals[202] */ + {0x0F12, 0x5004}, /* #TVAR_afit_pBaseVals[203] */ + {0x0F12, 0x0F40}, /* #TVAR_afit_pBaseVals[204] */ + {0x0F12, 0x400F}, /* #TVAR_afit_pBaseVals[205] */ + {0x0F12, 0x0204}, /* #TVAR_afit_pBaseVals[206] */ + {0x0F12, 0x0003}, /* #TVAR_afit_pBaseVals[207] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[208] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[209] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[210] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[211] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[212] */ + {0x0F12, 0x00C4}, /* #TVAR_afit_pBaseVals[213] */ + {0x0F12, 0x03FF}, /* #TVAR_afit_pBaseVals[214] */ + {0x0F12, 0x009C}, /* #TVAR_afit_pBaseVals[215] */ + {0x0F12, 0x017C}, /* #TVAR_afit_pBaseVals[216] */ + {0x0F12, 0x03FF}, /* #TVAR_afit_pBaseVals[217] */ + {0x0F12, 0x000C}, /* #TVAR_afit_pBaseVals[218] */ + {0x0F12, 0x0010}, /* #TVAR_afit_pBaseVals[219] */ + {0x0F12, 0x0104}, /* #TVAR_afit_pBaseVals[220] */ + {0x0F12, 0x03E8}, /* #TVAR_afit_pBaseVals[221] */ + {0x0F12, 0x0023}, /* #TVAR_afit_pBaseVals[222] */ + {0x0F12, 0x012C}, /* #TVAR_afit_pBaseVals[223] */ + {0x0F12, 0x0070}, /* #TVAR_afit_pBaseVals[224] */ + {0x0F12, 0x0004}, /* #TVAR_afit_pBaseVals[225] */ + {0x0F12, 0x0004}, /* #TVAR_afit_pBaseVals[226] */ + {0x0F12, 0x01AA}, /* #TVAR_afit_pBaseVals[227] */ + {0x0F12, 0x001E}, /* #TVAR_afit_pBaseVals[228] */ + {0x0F12, 0x001E}, /* #TVAR_afit_pBaseVals[229] */ + {0x0F12, 0x0005}, /* #TVAR_afit_pBaseVals[230] */ + {0x0F12, 0x0005}, /* #TVAR_afit_pBaseVals[231] */ + {0x0F12, 0x0064}, /* #TVAR_afit_pBaseVals[232] */ + {0x0F12, 0x0024}, /* #TVAR_afit_pBaseVals[233] */ + {0x0F12, 0x002A}, /* #TVAR_afit_pBaseVals[234] */ + {0x0F12, 0x0024}, /* #TVAR_afit_pBaseVals[235] */ + {0x0F12, 0x002A}, /* #TVAR_afit_pBaseVals[236] */ + {0x0F12, 0x0024}, /* #TVAR_afit_pBaseVals[237] */ + {0x0F12, 0x0A24}, /* #TVAR_afit_pBaseVals[238] */ + {0x0F12, 0x1701}, /* #TVAR_afit_pBaseVals[239] */ + {0x0F12, 0x0229}, /* #TVAR_afit_pBaseVals[240] */ + {0x0F12, 0x1403}, /* #TVAR_afit_pBaseVals[241] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[242] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[243] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[244] */ + {0x0F12, 0x00FF}, /* #TVAR_afit_pBaseVals[245] */ + {0x0F12, 0x043B}, /* #TVAR_afit_pBaseVals[246] */ + {0x0F12, 0x1414}, /* #TVAR_afit_pBaseVals[247] */ + {0x0F12, 0x0301}, /* #TVAR_afit_pBaseVals[248] */ + {0x0F12, 0xFF07}, /* #TVAR_afit_pBaseVals[249] */ + {0x0F12, 0x051E}, /* #TVAR_afit_pBaseVals[250] */ + {0x0F12, 0x0A1E}, /* #TVAR_afit_pBaseVals[251] */ + {0x0F12, 0x0F0F}, /* #TVAR_afit_pBaseVals[252] */ + {0x0F12, 0x0A04}, /* #TVAR_afit_pBaseVals[253] */ + {0x0F12, 0x0A3C}, /* #TVAR_afit_pBaseVals[254] */ + {0x0F12, 0x0528}, /* #TVAR_afit_pBaseVals[255] */ + {0x0F12, 0x0002}, /* #TVAR_afit_pBaseVals[256] */ + {0x0F12, 0x00FF}, /* #TVAR_afit_pBaseVals[257] */ + {0x0F12, 0x1002}, /* #TVAR_afit_pBaseVals[258] */ + {0x0F12, 0x001D}, /* #TVAR_afit_pBaseVals[259] */ + {0x0F12, 0x0900}, /* #TVAR_afit_pBaseVals[260] */ + {0x0F12, 0x0600}, /* #TVAR_afit_pBaseVals[261] */ + {0x0F12, 0x0504}, /* #TVAR_afit_pBaseVals[262] */ + {0x0F12, 0x0305}, /* #TVAR_afit_pBaseVals[263] */ + {0x0F12, 0x7803}, /* #TVAR_afit_pBaseVals[264] */ + {0x0F12, 0x0080}, /* #TVAR_afit_pBaseVals[265] */ + {0x0F12, 0x0080}, /* #TVAR_afit_pBaseVals[266] */ + {0x0F12, 0x0080}, /* #TVAR_afit_pBaseVals[267] */ + {0x0F12, 0x2323}, /* #TVAR_afit_pBaseVals[268] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[269] */ + {0x0F12, 0x2A02}, /* #TVAR_afit_pBaseVals[270] */ + {0x0F12, 0x462A}, /* #TVAR_afit_pBaseVals[271] */ + {0x0F12, 0x2846}, /* #TVAR_afit_pBaseVals[272] */ + {0x0F12, 0x0A00}, /* #TVAR_afit_pBaseVals[273] */ + {0x0F12, 0x1403}, /* #TVAR_afit_pBaseVals[274] */ + {0x0F12, 0x1E0C}, /* #TVAR_afit_pBaseVals[275] */ + {0x0F12, 0x070A}, /* #TVAR_afit_pBaseVals[276] */ + {0x0F12, 0x32FF}, /* #TVAR_afit_pBaseVals[277] */ + {0x0F12, 0x5A04}, /* #TVAR_afit_pBaseVals[278] */ + {0x0F12, 0x0F40}, /* #TVAR_afit_pBaseVals[279] */ + {0x0F12, 0x400F}, /* #TVAR_afit_pBaseVals[280] */ + {0x0F12, 0x0204}, /* #TVAR_afit_pBaseVals[281] */ + {0x0F12, 0x2303}, /* #TVAR_afit_pBaseVals[282] */ + {0x0F12, 0x0123}, /* #TVAR_afit_pBaseVals[283] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[284] */ + {0x0F12, 0x262A}, /* #TVAR_afit_pBaseVals[285] */ + {0x0F12, 0x2C2C}, /* #TVAR_afit_pBaseVals[286] */ + {0x0F12, 0x0028}, /* #TVAR_afit_pBaseVals[287] */ + {0x0F12, 0x030A}, /* #TVAR_afit_pBaseVals[288] */ + {0x0F12, 0x0714}, /* #TVAR_afit_pBaseVals[289] */ + {0x0F12, 0x0A1E}, /* #TVAR_afit_pBaseVals[290] */ + {0x0F12, 0xFF07}, /* #TVAR_afit_pBaseVals[291] */ + {0x0F12, 0x0432}, /* #TVAR_afit_pBaseVals[292] */ + {0x0F12, 0x4050}, /* #TVAR_afit_pBaseVals[293] */ + {0x0F12, 0x0F0F}, /* #TVAR_afit_pBaseVals[294] */ + {0x0F12, 0x0440}, /* #TVAR_afit_pBaseVals[295] */ + {0x0F12, 0x0302}, /* #TVAR_afit_pBaseVals[296] */ + {0x0F12, 0x2323}, /* #TVAR_afit_pBaseVals[297] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[298] */ + {0x0F12, 0x2A01}, /* #TVAR_afit_pBaseVals[299] */ + {0x0F12, 0x2C26}, /* #TVAR_afit_pBaseVals[300] */ + {0x0F12, 0x282C}, /* #TVAR_afit_pBaseVals[301] */ + {0x0F12, 0x0A00}, /* #TVAR_afit_pBaseVals[302] */ + {0x0F12, 0x1403}, /* #TVAR_afit_pBaseVals[303] */ + {0x0F12, 0x1E07}, /* #TVAR_afit_pBaseVals[304] */ + {0x0F12, 0x070A}, /* #TVAR_afit_pBaseVals[305] */ + {0x0F12, 0x32FF}, /* #TVAR_afit_pBaseVals[306] */ + {0x0F12, 0x5004}, /* #TVAR_afit_pBaseVals[307] */ + {0x0F12, 0x0F40}, /* #TVAR_afit_pBaseVals[308] */ + {0x0F12, 0x400F}, /* #TVAR_afit_pBaseVals[309] */ + {0x0F12, 0x0204}, /* #TVAR_afit_pBaseVals[310] */ + {0x0F12, 0x0003}, /* #TVAR_afit_pBaseVals[311] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[312] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[313] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[314] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[315] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[316] */ + {0x0F12, 0x00C4}, /* #TVAR_afit_pBaseVals[317] */ + {0x0F12, 0x03FF}, /* #TVAR_afit_pBaseVals[318] */ + {0x0F12, 0x009C}, /* #TVAR_afit_pBaseVals[319] */ + {0x0F12, 0x017C}, /* #TVAR_afit_pBaseVals[320] */ + {0x0F12, 0x03FF}, /* #TVAR_afit_pBaseVals[321] */ + {0x0F12, 0x000C}, /* #TVAR_afit_pBaseVals[322] */ + {0x0F12, 0x0010}, /* #TVAR_afit_pBaseVals[323] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[324] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[325] */ + {0x0F12, 0x0023}, /* #TVAR_afit_pBaseVals[326] */ + {0x0F12, 0x012C}, /* #TVAR_afit_pBaseVals[327] */ + {0x0F12, 0x0070}, /* #TVAR_afit_pBaseVals[328] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[329] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[330] */ + {0x0F12, 0x01AA}, /* #TVAR_afit_pBaseVals[331] */ + {0x0F12, 0x001E}, /* #TVAR_afit_pBaseVals[332] */ + {0x0F12, 0x001E}, /* #TVAR_afit_pBaseVals[333] */ + {0x0F12, 0x000A}, /* #TVAR_afit_pBaseVals[334] */ + {0x0F12, 0x000A}, /* #TVAR_afit_pBaseVals[335] */ + {0x0F12, 0x00E6}, /* #TVAR_afit_pBaseVals[336] */ + {0x0F12, 0x0032}, /* #TVAR_afit_pBaseVals[337] */ + {0x0F12, 0x0032}, /* #TVAR_afit_pBaseVals[338] */ + {0x0F12, 0x0028}, /* #TVAR_afit_pBaseVals[339] */ + {0x0F12, 0x0032}, /* #TVAR_afit_pBaseVals[340] */ + {0x0F12, 0x0028}, /* #TVAR_afit_pBaseVals[341] */ + {0x0F12, 0x0A24}, /* #TVAR_afit_pBaseVals[342] */ + {0x0F12, 0x1701}, /* #TVAR_afit_pBaseVals[343] */ + {0x0F12, 0x0229}, /* #TVAR_afit_pBaseVals[344] */ + {0x0F12, 0x1403}, /* #TVAR_afit_pBaseVals[345] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[346] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[347] */ + {0x0F12, 0x0504}, /* #TVAR_afit_pBaseVals[348] */ + {0x0F12, 0x00FF}, /* #TVAR_afit_pBaseVals[349] */ + {0x0F12, 0x043B}, /* #TVAR_afit_pBaseVals[350] */ + {0x0F12, 0x1414}, /* #TVAR_afit_pBaseVals[351] */ + {0x0F12, 0x0301}, /* #TVAR_afit_pBaseVals[352] */ + {0x0F12, 0xFF07}, /* #TVAR_afit_pBaseVals[353] */ + {0x0F12, 0x051E}, /* #TVAR_afit_pBaseVals[354] */ + {0x0F12, 0x0A1E}, /* #TVAR_afit_pBaseVals[355] */ + {0x0F12, 0x0F0F}, /* #TVAR_afit_pBaseVals[356] */ + {0x0F12, 0x0A04}, /* #TVAR_afit_pBaseVals[357] */ + {0x0F12, 0x0A3C}, /* #TVAR_afit_pBaseVals[358] */ + {0x0F12, 0x0532}, /* #TVAR_afit_pBaseVals[359] */ + {0x0F12, 0x0002}, /* #TVAR_afit_pBaseVals[360] */ + {0x0F12, 0x00FF}, /* #TVAR_afit_pBaseVals[361] */ + {0x0F12, 0x1002}, /* #TVAR_afit_pBaseVals[362] */ + {0x0F12, 0x001D}, /* #TVAR_afit_pBaseVals[363] */ + {0x0F12, 0x0900}, /* #TVAR_afit_pBaseVals[364] */ + {0x0F12, 0x0600}, /* #TVAR_afit_pBaseVals[365] */ + {0x0F12, 0x0504}, /* #TVAR_afit_pBaseVals[366] */ + {0x0F12, 0x0305}, /* #TVAR_afit_pBaseVals[367] */ + {0x0F12, 0x7802}, /* #TVAR_afit_pBaseVals[368] */ + {0x0F12, 0x0080}, /* #TVAR_afit_pBaseVals[369] */ + {0x0F12, 0x0080}, /* #TVAR_afit_pBaseVals[370] */ + {0x0F12, 0x0080}, /* #TVAR_afit_pBaseVals[371] */ + {0x0F12, 0x2328}, /* #TVAR_afit_pBaseVals[372] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[373] */ + {0x0F12, 0x2A02}, /* #TVAR_afit_pBaseVals[374] */ + {0x0F12, 0x2628}, /* #TVAR_afit_pBaseVals[375] */ + {0x0F12, 0x2826}, /* #TVAR_afit_pBaseVals[376] */ + {0x0F12, 0x0A00}, /* #TVAR_afit_pBaseVals[377] */ + {0x0F12, 0x1903}, /* #TVAR_afit_pBaseVals[378] */ + {0x0F12, 0x1E0F}, /* #TVAR_afit_pBaseVals[379] */ + {0x0F12, 0x070A}, /* #TVAR_afit_pBaseVals[380] */ + {0x0F12, 0x32FF}, /* #TVAR_afit_pBaseVals[381] */ + {0x0F12, 0x7804}, /* #TVAR_afit_pBaseVals[382] */ + {0x0F12, 0x0F40}, /* #TVAR_afit_pBaseVals[383] */ + {0x0F12, 0x400F}, /* #TVAR_afit_pBaseVals[384] */ + {0x0F12, 0x0204}, /* #TVAR_afit_pBaseVals[385] */ + {0x0F12, 0x2803}, /* #TVAR_afit_pBaseVals[386] */ + {0x0F12, 0x0123}, /* #TVAR_afit_pBaseVals[387] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[388] */ + {0x0F12, 0x2024}, /* #TVAR_afit_pBaseVals[389] */ + {0x0F12, 0x1C1C}, /* #TVAR_afit_pBaseVals[390] */ + {0x0F12, 0x0028}, /* #TVAR_afit_pBaseVals[391] */ + {0x0F12, 0x030A}, /* #TVAR_afit_pBaseVals[392] */ + {0x0F12, 0x0A0A}, /* #TVAR_afit_pBaseVals[393] */ + {0x0F12, 0x0A2D}, /* #TVAR_afit_pBaseVals[394] */ + {0x0F12, 0xFF07}, /* #TVAR_afit_pBaseVals[395] */ + {0x0F12, 0x0432}, /* #TVAR_afit_pBaseVals[396] */ + {0x0F12, 0x4050}, /* #TVAR_afit_pBaseVals[397] */ + {0x0F12, 0x0F0F}, /* #TVAR_afit_pBaseVals[398] */ + {0x0F12, 0x0440}, /* #TVAR_afit_pBaseVals[399] */ + {0x0F12, 0x0302}, /* #TVAR_afit_pBaseVals[400] */ + {0x0F12, 0x2328}, /* #TVAR_afit_pBaseVals[401] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[402] */ + {0x0F12, 0x3C01}, /* #TVAR_afit_pBaseVals[403] */ + {0x0F12, 0x1C3C}, /* #TVAR_afit_pBaseVals[404] */ + {0x0F12, 0x281C}, /* #TVAR_afit_pBaseVals[405] */ + {0x0F12, 0x0A00}, /* #TVAR_afit_pBaseVals[406] */ + {0x0F12, 0x0A03}, /* #TVAR_afit_pBaseVals[407] */ + {0x0F12, 0x2D0A}, /* #TVAR_afit_pBaseVals[408] */ + {0x0F12, 0x070A}, /* #TVAR_afit_pBaseVals[409] */ + {0x0F12, 0x32FF}, /* #TVAR_afit_pBaseVals[410] */ + {0x0F12, 0x5004}, /* #TVAR_afit_pBaseVals[411] */ + {0x0F12, 0x0F40}, /* #TVAR_afit_pBaseVals[412] */ + {0x0F12, 0x400F}, /* #TVAR_afit_pBaseVals[413] */ + {0x0F12, 0x0204}, /* #TVAR_afit_pBaseVals[414] */ + {0x0F12, 0x0003}, /* #TVAR_afit_pBaseVals[415] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[416] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[417] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[418] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[419] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[420] */ + {0x0F12, 0x00C4}, /* #TVAR_afit_pBaseVals[421] */ + {0x0F12, 0x03FF}, /* #TVAR_afit_pBaseVals[422] */ + {0x0F12, 0x009C}, /* #TVAR_afit_pBaseVals[423] */ + {0x0F12, 0x017C}, /* #TVAR_afit_pBaseVals[424] */ + {0x0F12, 0x03FF}, /* #TVAR_afit_pBaseVals[425] */ + {0x0F12, 0x000C}, /* #TVAR_afit_pBaseVals[426] */ + {0x0F12, 0x0010}, /* #TVAR_afit_pBaseVals[427] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[428] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[429] */ + {0x0F12, 0x003C}, /* #TVAR_afit_pBaseVals[430] */ + {0x0F12, 0x006F}, /* #TVAR_afit_pBaseVals[431] */ + {0x0F12, 0x0070}, /* #TVAR_afit_pBaseVals[432] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[433] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[434] */ + {0x0F12, 0x01AA}, /* #TVAR_afit_pBaseVals[435] */ + {0x0F12, 0x0014}, /* #TVAR_afit_pBaseVals[436] */ + {0x0F12, 0x0014}, /* #TVAR_afit_pBaseVals[437] */ + {0x0F12, 0x000A}, /* #TVAR_afit_pBaseVals[438] */ + {0x0F12, 0x000A}, /* #TVAR_afit_pBaseVals[439] */ + {0x0F12, 0x0122}, /* #TVAR_afit_pBaseVals[440] */ + {0x0F12, 0x003C}, /* #TVAR_afit_pBaseVals[441] */ + {0x0F12, 0x0032}, /* #TVAR_afit_pBaseVals[442] */ + {0x0F12, 0x0023}, /* #TVAR_afit_pBaseVals[443] */ + {0x0F12, 0x0023}, /* #TVAR_afit_pBaseVals[444] */ + {0x0F12, 0x0032}, /* #TVAR_afit_pBaseVals[445] */ + {0x0F12, 0x0A24}, /* #TVAR_afit_pBaseVals[446] */ + {0x0F12, 0x1701}, /* #TVAR_afit_pBaseVals[447] */ + {0x0F12, 0x0229}, /* #TVAR_afit_pBaseVals[448] */ + {0x0F12, 0x1403}, /* #TVAR_afit_pBaseVals[449] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[450] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[451] */ + {0x0F12, 0x0505}, /* #TVAR_afit_pBaseVals[452] */ + {0x0F12, 0x00FF}, /* #TVAR_afit_pBaseVals[453] */ + {0x0F12, 0x043B}, /* #TVAR_afit_pBaseVals[454] */ + {0x0F12, 0x1414}, /* #TVAR_afit_pBaseVals[455] */ + {0x0F12, 0x0301}, /* #TVAR_afit_pBaseVals[456] */ + {0x0F12, 0xFF07}, /* #TVAR_afit_pBaseVals[457] */ + {0x0F12, 0x051E}, /* #TVAR_afit_pBaseVals[458] */ + {0x0F12, 0x0A1E}, /* #TVAR_afit_pBaseVals[459] */ + {0x0F12, 0x0000}, /* #TVAR_afit_pBaseVals[460] */ + {0x0F12, 0x0A04}, /* #TVAR_afit_pBaseVals[461] */ + {0x0F12, 0x0A3C}, /* #TVAR_afit_pBaseVals[462] */ + {0x0F12, 0x0532}, /* #TVAR_afit_pBaseVals[463] */ + {0x0F12, 0x0002}, /* #TVAR_afit_pBaseVals[464] */ + {0x0F12, 0x0096}, /* #TVAR_afit_pBaseVals[465] */ + {0x0F12, 0x1002}, /* #TVAR_afit_pBaseVals[466] */ + {0x0F12, 0x001E}, /* #TVAR_afit_pBaseVals[467] */ + {0x0F12, 0x0900}, /* #TVAR_afit_pBaseVals[468] */ + {0x0F12, 0x0600}, /* #TVAR_afit_pBaseVals[469] */ + {0x0F12, 0x0504}, /* #TVAR_afit_pBaseVals[470] */ + {0x0F12, 0x0305}, /* #TVAR_afit_pBaseVals[471] */ + {0x0F12, 0x7D02}, /* #TVAR_afit_pBaseVals[472] */ + {0x0F12, 0x0080}, /* #TVAR_afit_pBaseVals[473] */ + {0x0F12, 0x0080}, /* #TVAR_afit_pBaseVals[474] */ + {0x0F12, 0x0080}, /* #TVAR_afit_pBaseVals[475] */ + {0x0F12, 0x5050}, /* #TVAR_afit_pBaseVals[476] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[477] */ + {0x0F12, 0x1C02}, /* #TVAR_afit_pBaseVals[478] */ + {0x0F12, 0x191C}, /* #TVAR_afit_pBaseVals[479] */ + {0x0F12, 0x2819}, /* #TVAR_afit_pBaseVals[480] */ + {0x0F12, 0x0A00}, /* #TVAR_afit_pBaseVals[481] */ + {0x0F12, 0x1E03}, /* #TVAR_afit_pBaseVals[482] */ + {0x0F12, 0x1E0F}, /* #TVAR_afit_pBaseVals[483] */ + {0x0F12, 0x0508}, /* #TVAR_afit_pBaseVals[484] */ + {0x0F12, 0x32FF}, /* #TVAR_afit_pBaseVals[485] */ + {0x0F12, 0x8204}, /* #TVAR_afit_pBaseVals[486] */ + {0x0F12, 0x1448}, /* #TVAR_afit_pBaseVals[487] */ + {0x0F12, 0x4015}, /* #TVAR_afit_pBaseVals[488] */ + {0x0F12, 0x0204}, /* #TVAR_afit_pBaseVals[489] */ + {0x0F12, 0x5003}, /* #TVAR_afit_pBaseVals[490] */ + {0x0F12, 0x0150}, /* #TVAR_afit_pBaseVals[491] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[492] */ + {0x0F12, 0x1E1E}, /* #TVAR_afit_pBaseVals[493] */ + {0x0F12, 0x1212}, /* #TVAR_afit_pBaseVals[494] */ + {0x0F12, 0x0028}, /* #TVAR_afit_pBaseVals[495] */ + {0x0F12, 0x030A}, /* #TVAR_afit_pBaseVals[496] */ + {0x0F12, 0x0A10}, /* #TVAR_afit_pBaseVals[497] */ + {0x0F12, 0x0819}, /* #TVAR_afit_pBaseVals[498] */ + {0x0F12, 0xFF05}, /* #TVAR_afit_pBaseVals[499] */ + {0x0F12, 0x0432}, /* #TVAR_afit_pBaseVals[500] */ + {0x0F12, 0x4052}, /* #TVAR_afit_pBaseVals[501] */ + {0x0F12, 0x1514}, /* #TVAR_afit_pBaseVals[502] */ + {0x0F12, 0x0440}, /* #TVAR_afit_pBaseVals[503] */ + {0x0F12, 0x0302}, /* #TVAR_afit_pBaseVals[504] */ + {0x0F12, 0x5050}, /* #TVAR_afit_pBaseVals[505] */ + {0x0F12, 0x0101}, /* #TVAR_afit_pBaseVals[506] */ + {0x0F12, 0x1E01}, /* #TVAR_afit_pBaseVals[507] */ + {0x0F12, 0x121E}, /* #TVAR_afit_pBaseVals[508] */ + {0x0F12, 0x2812}, /* #TVAR_afit_pBaseVals[509] */ + {0x0F12, 0x0A00}, /* #TVAR_afit_pBaseVals[510] */ + {0x0F12, 0x1003}, /* #TVAR_afit_pBaseVals[511] */ + {0x0F12, 0x190A}, /* #TVAR_afit_pBaseVals[512] */ + {0x0F12, 0x0508}, /* #TVAR_afit_pBaseVals[513] */ + {0x0F12, 0x32FF}, /* #TVAR_afit_pBaseVals[514] */ + {0x0F12, 0x5204}, /* #TVAR_afit_pBaseVals[515] */ + {0x0F12, 0x1440}, /* #TVAR_afit_pBaseVals[516] */ + {0x0F12, 0x4015}, /* #TVAR_afit_pBaseVals[517] */ + {0x0F12, 0x0204}, /* #TVAR_afit_pBaseVals[518] */ + {0x0F12, 0x0003}, /* #TVAR_afit_pBaseVals[519] */ + + /* Update Changed Registers */ + {0x002A, 0x0664}, + {0x0F12, 0x013E}, /* seti_uContrastCenter */ + + /* ====== SET PLL ===== */ + /* How to set */ + /* 1. MCLK */ + /* hex(CLK you want) * 1000) */ + /* 2.System CLK */ + /* hex((CLK you want) * 1000 / 4) */ + /* 3.PCLK */ + /* hex((CLK you want) * 1000 / 4) */ + + /* Set input CLK */ + {0x002A, 0x01CC}, + {0x0F12, 0x5DC0}, /* #REG_TC_IPRM_InClockLSBs */ + {0x0F12, 0x0000}, + {0x002A, 0x01EE}, + {0x0F12, 0x0003}, /* #REG_TC_IPRM_UseNPviClocks - Number of PLL setting */ + /* Set system CLK - 32MHz(0x1F40), 58MHz(0x38a4), can be 24MHz lowest */ + {0x002A, 0x01F6}, + /*{0x0F12, 0x38a4}, */ /* @0x700001F6 First system clock frequency in KHz divided by 4 - 58.000MHz */ + {0x0F12, 0x2EE0}, /* 48MHz 1st SYS_CLK */ + {0x0F12, 0x1770}, /* 24MHz REG_TC_IPRM_MinOutRate4KHz_0 */ + {0x0F12, 0x1780}, /* 24.064MHz REG_TC_IPRM_MaxOutRate4KHz_0 */ + {0x0F12, 0x2710}, /* 40MHz 2nd SYS_CLK, for capture */ + {0x0F12, 0x2700}, /* 39.936MHz REG_TC_IPRM_MinOutRate4KHz_1, for capture */ + {0x0F12, 0x2720}, /* 40.064MHz REG_TC_IPRM_MaxOutRate4KHz_1 */ + {0x0F12, 0x38a4}, + {0x0F12, 0x2310}, + {0x0F12, 0x2340}, + /* Update PLL */ + {0x002A, 0x0208}, + {0x0F12, 0x0001}, /* #REG_TC_IPRM_InitParamsUpdated */ +}; + + +/* Initialization sequence for 480x272 resolution */ +const uint16_t S5K5CAG_480x272[][2]= +{ + /* SET PREVIEW CONFIGURATION_0, Camera Normal 10~30fps */ + /*# Size: 480x272 */ + {0x0028, 0x7000}, /* SET PREVIEW CONFIGURATION_0 */ + {0x002A, 0x026C}, /* SET PREVIEW CONFIGURATION_0 */ + {0x0F12, 0x01e0}, /* #REG_0TC_PCFG_usWidth - 480 */ + {0x0F12, 0x0110}, /* #REG_0TC_PCFG_usHeight - 272 */ + {0x0F12, 0x0000}, /* #REG_0TC_PCFG_Format */ + {0x0F12, 0x1780}, /* #REG_0TC_PCFG_usMaxOut4KHzRate - 24.064MHz */ + {0x0F12, 0x1760}, /* #REG_0TC_PCFG_usMinOut4KHzRate - 23.936MHz */ + {0x0F12, 0x0100}, /* #REG_0TC_PCFG_OutClkPerPix88 */ + {0x0F12, 0x0800}, /* #REG_0TC_PCFG_uMaxBpp88 */ + /* #REG_0TC_PCFG_PVIMask */ + /* bit0: swap RGB high/low byte */ + /* bit2: VSYNC data blanking level */ + /* bit3: HSYNC data blanking level */ + /*{0x0F12, 0x0052}, */ /* #REG_0TC_PCFG_PVIMask - s0050 = FALSE in MSM6290 : s0052 = TRUE in MSM6800 - reg 027A */ + {0x0F12, 0x005F}, /* #REG_0TC_PCFG_PVIMask - bit0: swap RGB high/low byte */ + {0x0F12, 0x4000}, /* #REG_0TC_PCFG_OIFMask */ + {0x0F12, 0x0400}, /* #REG_0TC_PCFG_usJpegPacketSize */ + {0x0F12, 0x0258}, /* #REG_0TC_PCFG_usJpegTotalPackets */ + {0x0F12, 0x0000}, /* #REG_0TC_PCFG_uClockInd */ + {0x0F12, 0x0000}, /* #REG_0TC_PCFG_usFrTimeType */ + {0x0F12, 0x0002}, /* #REG_0TC_PCFG_FrRateQualityType 01:Always achieve the best frame rate. 02:Always achieve the best possible image quality (no-binning mode) */ + /*=================S5K5CAGX_CAM_NOM_MAX_FR_TIME,S5K5CAGX_CAM_NOM_MIN_FR_TIME 30fps~15fps (Arima Use)==================*/ + {0x0F12, 0x03E8}, /* #REG_0TC_PCFG_usMaxFrTimeMsecMult10 - 10fps */ + {0x0F12, 0x029A}, /* #REG_0TC_PCFG_usMaxFrTimeMsecMult10 - 15fps */ + /*{0x0F12, 0x014D},*/ /* #REG_0TC_PCFG_usMinFrTimeMsecMult10 - 30fps */ + /*==========================================================================================*/ + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + + /* New Configuration FW Sync Preview */ + {0x002A, 0x023C}, + {0x0F12, 0x0000}, + {0x002A, 0x0240}, + {0x0F12, 0x0001}, + {0x002A, 0x0230}, + {0x0F12, 0x0001}, + {0x002A, 0x023E}, + {0x0F12, 0x0001}, + {0x002A, 0x0220}, + {0x0F12, 0x0001}, + {0x0F12, 0x0001}, + + {0x0028, 0xD000}, + {0x002A, 0x1000}, + {0x0F12, 0x0001}, +}; + +/* Initialization sequence for VGA resolution (640x480)*/ +const uint16_t S5K5CAG_VGA[][2]= +{ + /* SET PREVIEW CONFIGURATION_0, Camera Normal 10~30fps */ + /*# Size: VGA 640x480 */ + {0x0028, 0x7000}, /* SET PREVIEW CONFIGURATION_0 */ + {0x002A, 0x026C}, /* SET PREVIEW CONFIGURATION_0 */ + {0x0F12, 0x0280}, /* #REG_0TC_PCFG_usWidth - 640 */ + {0x0F12, 0x01E0}, /* #REG_0TC_PCFG_usHeight - 480 */ + {0x0F12, 0x0000}, /* #REG_0TC_PCFG_Format */ + {0x0F12, 0x1780}, /* #REG_0TC_PCFG_usMaxOut4KHzRate - 24.064MHz */ + {0x0F12, 0x1760}, /* #REG_0TC_PCFG_usMinOut4KHzRate - 23.936MHz */ + {0x0F12, 0x0100}, /* #REG_0TC_PCFG_OutClkPerPix88 */ + {0x0F12, 0x0800}, /* #REG_0TC_PCFG_uMaxBpp88 */ + /* #REG_0TC_PCFG_PVIMask */ + /* bit0: swap RGB high/low byte */ + /* bit2: VSYNC data blanking level */ + /* bit3: HSYNC data blanking level */ + /*{0x0F12, 0x0052}, */ /* #REG_0TC_PCFG_PVIMask - s0050 = FALSE in MSM6290 : s0052 = TRUE in MSM6800 - reg 027A */ + {0x0F12, 0x005F}, /* #REG_0TC_PCFG_PVIMask - bit0: swap RGB high/low byte */ + {0x0F12, 0x4000}, /* #REG_0TC_PCFG_OIFMask */ + {0x0F12, 0x0400}, /* #REG_0TC_PCFG_usJpegPacketSize */ + {0x0F12, 0x0258}, /* #REG_0TC_PCFG_usJpegTotalPackets */ + {0x0F12, 0x0000}, /* #REG_0TC_PCFG_uClockInd */ + {0x0F12, 0x0000}, /* #REG_0TC_PCFG_usFrTimeType */ + {0x0F12, 0x0002}, /* #REG_0TC_PCFG_FrRateQualityType 01:Always achieve the best frame rate. 02:Always achieve the best possible image quality (no-binning mode) */ + /*=================S5K5CAGX_CAM_NOM_MAX_FR_TIME,S5K5CAGX_CAM_NOM_MIN_FR_TIME 30fps~15fps (Arima Use)==================*/ + {0x0F12, 0x03E8}, /* #REG_0TC_PCFG_usMaxFrTimeMsecMult10 - 10fps */ + {0x0F12, 0x029A}, /* #REG_0TC_PCFG_usMaxFrTimeMsecMult10 - 15fps */ + /*0x0F12, 0x014D,*/ /* #REG_0TC_PCFG_usMinFrTimeMsecMult10 - 30fps */ + /*==========================================================================================*/ + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + + /* New Configuration FW Sync Preview */ + {0x002A, 0x023C}, + {0x0F12, 0x0000}, + {0x002A, 0x0240}, + {0x0F12, 0x0001}, + {0x002A, 0x0230}, + {0x0F12, 0x0001}, + {0x002A, 0x023E}, + {0x0F12, 0x0001}, + {0x002A, 0x0220}, + {0x0F12, 0x0001}, + {0x0F12, 0x0001}, + + {0x0028, 0xD000}, + {0x002A, 0x1000}, + {0x0F12, 0x0001}, +}; + +/* Initialization sequence for QVGA resolution (320x240) */ +const uint16_t S5K5CAG_QVGA[][2]= +{ + /* SET PREVIEW CONFIGURATION_0, Camera Normal 10~30fps */ + /*# Size: QVGA 320x240 */ + {0x0028, 0x7000}, /* SET PREVIEW CONFIGURATION_0 */ + {0x002A, 0x026C}, /* SET PREVIEW CONFIGURATION_0 */ + {0x0F12, 0x0140}, /* #REG_0TC_PCFG_usWidth - 320 */ + {0x0F12, 0x00F0}, /* #REG_0TC_PCFG_usHeight - 240 */ + {0x0F12, 0x0000}, /* #REG_0TC_PCFG_Format */ + {0x0F12, 0x1780}, /* #REG_0TC_PCFG_usMaxOut4KHzRate - 24.064MHz */ + {0x0F12, 0x1760}, /* #REG_0TC_PCFG_usMinOut4KHzRate - 23.936MHz */ + {0x0F12, 0x0100}, /* #REG_0TC_PCFG_OutClkPerPix88 */ + {0x0F12, 0x0800}, /* #REG_0TC_PCFG_uMaxBpp88 */ + /* #REG_0TC_PCFG_PVIMask */ + /* bit0: swap RGB high/low byte */ + /* bit2: VSYNC data blanking level */ + /* bit3: HSYNC data blanking level */ + /*{0x0F12, 0x0052}, */ /* #REG_0TC_PCFG_PVIMask - s0050 = FALSE in MSM6290 : s0052 = TRUE in MSM6800 - reg 027A */ + {0x0F12, 0x005F}, /* #REG_0TC_PCFG_PVIMask - bit0: swap RGB high/low byte */ + {0x0F12, 0x4000}, /* #REG_0TC_PCFG_OIFMask */ + {0x0F12, 0x0400}, /* #REG_0TC_PCFG_usJpegPacketSize */ + {0x0F12, 0x0258}, /* #REG_0TC_PCFG_usJpegTotalPackets */ + {0x0F12, 0x0000}, /* #REG_0TC_PCFG_uClockInd */ + {0x0F12, 0x0000}, /* #REG_0TC_PCFG_usFrTimeType */ + {0x0F12, 0x0002}, /* #REG_0TC_PCFG_FrRateQualityType 01:Always achieve the best frame rate. 02:Always achieve the best possible image quality (no-binning mode) */ + /*=================S5K5CAGX_CAM_NOM_MAX_FR_TIME,S5K5CAGX_CAM_NOM_MIN_FR_TIME 30fps~15fps (Arima Use)==================*/ + {0x0F12, 0x03E8}, /* #REG_0TC_PCFG_usMaxFrTimeMsecMult10 - 10fps */ + {0x0F12, 0x029A}, /* #REG_0TC_PCFG_usMaxFrTimeMsecMult10 - 15fps */ + /*{0x0F12, 0x014D},*/ /* #REG_0TC_PCFG_usMinFrTimeMsecMult10 - 30fps */ + /*==========================================================================================*/ + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + + /* New Configuration FW Sync Preview */ + {0x002A, 0x023C}, + {0x0F12, 0x0000}, + {0x002A, 0x0240}, + {0x0F12, 0x0001}, + {0x002A, 0x0230}, + {0x0F12, 0x0001}, + {0x002A, 0x023E}, + {0x0F12, 0x0001}, + {0x002A, 0x0220}, + {0x0F12, 0x0001}, + {0x0F12, 0x0001}, + + {0x0028, 0xD000}, + {0x002A, 0x1000}, + {0x0F12, 0x0001}, +}; + +/* Initialization sequence for QQVGA resolution (160x120) */ +const uint16_t S5K5CAG_QQVGA[][2]= +{ + /* SET PREVIEW CONFIGURATION_0, Camera Normal 10~30fps */ + /*# Size: QQVGA 160x120 */ + {0x0028, 0x7000}, /* SET PREVIEW CONFIGURATION_0 */ + {0x002A, 0x026C}, /* SET PREVIEW CONFIGURATION_0 */ + {0x0F12, 0x00A0}, /* #REG_0TC_PCFG_usWidth - 160 */ + {0x0F12, 0x0078}, /* #REG_0TC_PCFG_usHeight - 120 */ + {0x0F12, 0x0000}, /* #REG_0TC_PCFG_Format */ + {0x0F12, 0x1780}, /* #REG_0TC_PCFG_usMaxOut4KHzRate - 24.064MHz */ + {0x0F12, 0x1760}, /* #REG_0TC_PCFG_usMinOut4KHzRate - 23.936MHz */ + {0x0F12, 0x0100}, /* #REG_0TC_PCFG_OutClkPerPix88 */ + {0x0F12, 0x0800}, /* #REG_0TC_PCFG_uMaxBpp88 */ + /* #REG_0TC_PCFG_PVIMask */ + /* bit0: swap RGB high/low byte */ + /* bit2: VSYNC data blanking level */ + /* bit3: HSYNC data blanking level */ + /*{0x0F12, 0x0052}, */ /* #REG_0TC_PCFG_PVIMask - s0050 = FALSE in MSM6290 : s0052 = TRUE in MSM6800 - reg 027A */ + {0x0F12, 0x005F}, /* #REG_0TC_PCFG_PVIMask - bit0: swap RGB high/low byte */ + {0x0F12, 0x4000}, /* #REG_0TC_PCFG_OIFMask */ + {0x0F12, 0x0400}, /* #REG_0TC_PCFG_usJpegPacketSize */ + {0x0F12, 0x0258}, /* #REG_0TC_PCFG_usJpegTotalPackets */ + {0x0F12, 0x0000}, /* #REG_0TC_PCFG_uClockInd */ + {0x0F12, 0x0000}, /* #REG_0TC_PCFG_usFrTimeType */ + {0x0F12, 0x0002}, /* #REG_0TC_PCFG_FrRateQualityType 01:Always achieve the best frame rate. 02:Always achieve the best possible image quality (no-binning mode) */ + /*=================S5K5CAGX_CAM_NOM_MAX_FR_TIME,S5K5CAGX_CAM_NOM_MIN_FR_TIME 30fps~15fps (Arima Use)==================*/ + {0x0F12, 0x03E8}, /* #REG_0TC_PCFG_usMaxFrTimeMsecMult10 - 10fps */ + {0x0F12, 0x029A}, /* #REG_0TC_PCFG_usMaxFrTimeMsecMult10 - 15fps */ + /*{0x0F12, 0x014D},*/ /* #REG_0TC_PCFG_usMinFrTimeMsecMult10 - 30fps */ + /*==========================================================================================*/ + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + {0x0F12, 0x0000}, + + /* New Configuration FW Sync Preview */ + {0x002A, 0x023C}, + {0x0F12, 0x0000}, + {0x002A, 0x0240}, + {0x0F12, 0x0001}, + {0x002A, 0x0230}, + {0x0F12, 0x0001}, + {0x002A, 0x023E}, + {0x0F12, 0x0001}, + {0x002A, 0x0220}, + {0x0F12, 0x0001}, + {0x0F12, 0x0001}, + + {0x0028, 0xD000}, + {0x002A, 0x1000}, + {0x0F12, 0x0001}, +}; + +/** + * @} + */ + +/** @defgroup S5K5CAG_Private_Functions + * @{ + */ + +/** + * @brief Initializes the S5K5CAG CAMERA component. + * @param DeviceAddr: Device address on communication Bus. + * @param resolution: Camera resolution + * @retval None + */ +void s5k5cag_Init(uint16_t DeviceAddr, uint32_t resolution) +{ + uint32_t index; + + /* Initialize I2C */ + CAMERA_IO_Init(); + + if ((resolution == CAMERA_R160x120) || /* Check if resolution is supported */ + (resolution == CAMERA_R320x240) || + (resolution == CAMERA_R480x272) || + (resolution == CAMERA_R640x480)) + { + /* Set common parameters for all resolutions */ + for(index=0; index<(sizeof(S5K5CAG_Common)/4); index++) + { + if(0xFFFF == S5K5CAG_Common[index][0]) + { + CAMERA_Delay(S5K5CAG_Common[index][1]); + } + else + { + CAMERA_IO_Write(DeviceAddr, S5K5CAG_Common[index][0], S5K5CAG_Common[index][1]); + CAMERA_Delay(1); + } + } + + /* Set specific parameters for each resolution */ + switch (resolution) + { + case CAMERA_R160x120: + { + for(index=0; index<(sizeof(S5K5CAG_QQVGA)/4); index++) + { + CAMERA_IO_Write(DeviceAddr, S5K5CAG_QQVGA[index][0], S5K5CAG_QQVGA[index][1]); + CAMERA_Delay(1); + } + break; + } + case CAMERA_R320x240: + { + for(index=0; index<(sizeof(S5K5CAG_QVGA)/4); index++) + { + CAMERA_IO_Write(DeviceAddr, S5K5CAG_QVGA[index][0], S5K5CAG_QVGA[index][1]); + CAMERA_Delay(1); + } + break; + } + case CAMERA_R480x272: + { + for(index=0; index<(sizeof(S5K5CAG_480x272)/4); index++) + { + CAMERA_IO_Write(DeviceAddr, S5K5CAG_480x272[index][0], S5K5CAG_480x272[index][1]); + CAMERA_Delay(1); + } + break; + } + case CAMERA_R640x480: + { + for(index=0; index<(sizeof(S5K5CAG_VGA)/4); index++) + { + CAMERA_IO_Write(DeviceAddr, S5K5CAG_VGA[index][0], S5K5CAG_VGA[index][1]); + CAMERA_Delay(1); + } + break; + } + default: + { + break; + } + } + } +} + +/** + * @brief Configures the S5K5CAG camera feature. + * @param DeviceAddr: Device address on communication Bus. + * @param feature: Camera feature to be configured + * @param value: Value to be configured + * @param brightness_value: Brightness value to be configured + * @retval None + */ +void s5k5cag_Config(uint16_t DeviceAddr, uint32_t feature, uint32_t value, uint32_t brightness_value) +{ + uint32_t value_tmp; + uint32_t br_value; + uint32_t r_gain = 0xA0; + uint32_t g_gain = 0xA0; + uint32_t b_gain = 0xA0; + + /* Convert the input value into s5k5cag parameters */ + value_tmp = s5k5cag_ConvertValue(feature, value); + br_value = s5k5cag_ConvertValue(CAMERA_CONTRAST_BRIGHTNESS, brightness_value); + + switch(feature) + { + case CAMERA_BLACK_WHITE: + { + CAMERA_IO_Write(DeviceAddr, 0x0028, 0x7000); /* Reset previous color effect settings */ + CAMERA_IO_Write(DeviceAddr, 0x002A, 0x04D6); + CAMERA_IO_Write(DeviceAddr, 0x0F12, 0x0001); + CAMERA_Delay(100); /* Wait for 100ms */ + + CAMERA_IO_Write(DeviceAddr, 0x0028, 0x7000); /* REG_TC_GP_SpecialEffects register (0x70000021E) */ + CAMERA_IO_Write(DeviceAddr, 0x002A, 0x021E); /* REG_TC_GP_SpecialEffects register */ + CAMERA_IO_Write(DeviceAddr, 0x0F12, value_tmp); + break; + } + case CAMERA_CONTRAST_BRIGHTNESS: + { + /* Set brightness */ + CAMERA_IO_Write(DeviceAddr, 0x0028, 0x7000); /* REG_TC_UserBrightness register (0x70000020C) */ + CAMERA_IO_Write(DeviceAddr, 0x002A, 0x020C); /* REG_TC_UserBrightness register */ + CAMERA_IO_Write(DeviceAddr, 0x0F12, br_value); + + /* Set contrast */ + CAMERA_IO_Write(DeviceAddr, 0x0028, 0x7000); /* REG_TC_UserContrast register (0x70000020E) */ + CAMERA_IO_Write(DeviceAddr, 0x002A, 0x020E); /* REG_TC_UserContrast register */ + CAMERA_IO_Write(DeviceAddr, 0x0F12, value_tmp); + break; + } + case CAMERA_COLOR_EFFECT: + { + /* Reset previous color effect settings */ + CAMERA_IO_Write(DeviceAddr, 0x0028, 0x7000); /* REG_TC_DBG_ReInitCmd register (0x700004D6) */ + CAMERA_IO_Write(DeviceAddr, 0x002A, 0x04D6); /* REG_TC_DBG_ReInitCmd register */ + CAMERA_IO_Write(DeviceAddr, 0x0F12, 0x0001); + CAMERA_Delay(100); /* Wait for 100ms */ + + if (value_tmp == S5K5CAG_COLOR_EFFECT_ANTIQUE) + { + /* Sepia color effect */ + CAMERA_IO_Write(DeviceAddr, 0x0028, 0x7000); /* REG_TC_GP_SpecialEffects register (0x70000021E) */ + CAMERA_IO_Write(DeviceAddr, 0x002A, 0x021E); /* REG_TC_GP_SpecialEffects register */ + CAMERA_IO_Write(DeviceAddr, 0x0F12, value_tmp); + } + else + { + /* Reset previous special effect view, restore normal view */ + CAMERA_IO_Write(DeviceAddr, 0x0028, 0x7000); /* REG_TC_GP_SpecialEffects register (0x70000021E) */ + CAMERA_IO_Write(DeviceAddr, 0x002A, 0x021E); /* REG_TC_GP_SpecialEffects register */ + CAMERA_IO_Write(DeviceAddr, 0x0F12, S5K5CAG_BLACK_WHITE_NORMAL); + + switch(value_tmp) + { + case S5K5CAG_COLOR_EFFECT_RED : /* Red color effect */ + r_gain = 0xA0; /* Red gain set to a high level */ + g_gain = 0x40; /* Green gain set to a low level */ + b_gain = 0x50; /* Blue gain set to a low level */ + break; + + case S5K5CAG_COLOR_EFFECT_GREEN : /* Green color effect */ + r_gain = 0x60; /* Red gain set to a low level */ + g_gain = 0xA0; /* Green gain set to a high level */ + b_gain = 0x60; /* Blue gain set to a low level */ + break; + + case S5K5CAG_COLOR_EFFECT_BLUE : /* Blue color effect : */ + r_gain = 0x30; /* Red gain set to a low level */ + g_gain = 0x30; /* Green gain set to a low level */ + b_gain = 0xA0; /* Blue gain set to a high level */ + break; + default : /* No color effect applied */ + value_tmp = S5K5CAG_COLOR_EFFECT_NONE; + break; + } + + if (value_tmp != S5K5CAG_COLOR_EFFECT_NONE) + { + /* Set red gain */ + CAMERA_IO_Write(DeviceAddr, 0x0028, 0x7000); /* REG_SF_USER_Rgain register (0x700004A0) */ + CAMERA_IO_Write(DeviceAddr, 0x002A, 0x04A0); /* REG_SF_USER_Rgain register */ + CAMERA_IO_Write(DeviceAddr, 0x0F12, r_gain); + + CAMERA_IO_Write(DeviceAddr, 0x0028, 0x7000); /* REG_SF_USER_RgainChanged register (0x700004A2) */ + CAMERA_IO_Write(DeviceAddr, 0x002A, 0x04A2); /* REG_SF_USER_RgainChanged */ + CAMERA_IO_Write(DeviceAddr, 0x0F12, 0x1); + + /* Set green gain */ + CAMERA_IO_Write(DeviceAddr, 0x0028, 0x7000); /* REG_SF_USER_Ggain register (0x700004A4) */ + CAMERA_IO_Write(DeviceAddr, 0x002A, 0x04A4); /* REG_SF_USER_Ggain register */ + CAMERA_IO_Write(DeviceAddr, 0x0F12, g_gain); + + CAMERA_IO_Write(DeviceAddr, 0x0028, 0x7000); /* REG_SF_USER_GgainChanged register (0x700004A6) */ + CAMERA_IO_Write(DeviceAddr, 0x002A, 0x04A6); /* REG_SF_USER_GgainChanged */ + CAMERA_IO_Write(DeviceAddr, 0x0F12, 0x1); + + /* Set blue gain */ + CAMERA_IO_Write(DeviceAddr, 0x0028, 0x7000); /* REG_SF_USER_Bgain register (0x700004A8) */ + CAMERA_IO_Write(DeviceAddr, 0x002A, 0x04A8); /* REG_SF_USER_Bgain register */ + CAMERA_IO_Write(DeviceAddr, 0x0F12, b_gain); + + CAMERA_IO_Write(DeviceAddr, 0x0028, 0x7000); /* REG_SF_USER_BgainChanged register (0x700004AA) */ + CAMERA_IO_Write(DeviceAddr, 0x002A, 0x04AA); /* REG_SF_USER_BgainChanged */ + CAMERA_IO_Write(DeviceAddr, 0x0F12, 0x1); + } + } + break; + } + default: + { + break; + } + } +} + +/** + * @brief Read the S5K5CAG Camera identity. + * @param DeviceAddr: Device address on communication Bus. + * @retval the S5K5CAG ID + */ +uint16_t s5k5cag_ReadID(uint16_t DeviceAddr) +{ + /* Initialize I2C */ + CAMERA_IO_Init(); + + /* Prepare the sensor to read the Camera ID */ + CAMERA_IO_Write(DeviceAddr, 0xFCFC, 0x0000); /* page 0x0000 */ + + /* Get the camera ID */ + /* INFO_chipId1 @ 0x00000040 */ + return (CAMERA_IO_Read(DeviceAddr, S5K5CAG_INFO_CHIPID1)); +} + +/****************************************************************************** + Static Functions +*******************************************************************************/ +/** + * @brief Convert input values into s5k5cag parameters. + * @param feature: Camera feature to be configured + * @param value: Value to be configured + * @retval The converted value + */ +static uint32_t s5k5cag_ConvertValue(uint32_t feature, uint32_t value) +{ + uint32_t ret = 0; + + switch(feature) + { + case CAMERA_BLACK_WHITE: + { + switch(value) + { + case CAMERA_BLACK_WHITE_BW: + { + ret = S5K5CAG_BLACK_WHITE_BW; + break; + } + case CAMERA_BLACK_WHITE_NEGATIVE: + { + ret = S5K5CAG_BLACK_WHITE_NEGATIVE; + break; + } + case CAMERA_BLACK_WHITE_BW_NEGATIVE: + { + ret = S5K5CAG_BLACK_WHITE_BW_NEGATIVE; + break; + } + case CAMERA_BLACK_WHITE_NORMAL: + { + ret = S5K5CAG_BLACK_WHITE_NORMAL; + break; + } + default: + { + ret = S5K5CAG_BLACK_WHITE_NORMAL; + break; + } + } + break; + } + case CAMERA_CONTRAST_BRIGHTNESS: + { + switch(value) + { + case CAMERA_BRIGHTNESS_LEVEL0: + { + ret = S5K5CAG_BRIGHTNESS_LEVEL0; + break; + } + case CAMERA_BRIGHTNESS_LEVEL1: + { + ret = S5K5CAG_BRIGHTNESS_LEVEL1; + break; + } + case CAMERA_BRIGHTNESS_LEVEL2: + { + ret = S5K5CAG_BRIGHTNESS_LEVEL2; + break; + } + case CAMERA_BRIGHTNESS_LEVEL3: + { + ret = S5K5CAG_BRIGHTNESS_LEVEL3; + break; + } + case CAMERA_BRIGHTNESS_LEVEL4: + { + ret = S5K5CAG_BRIGHTNESS_LEVEL4; + break; + } + case CAMERA_CONTRAST_LEVEL0: + { + ret = S5K5CAG_CONTRAST_LEVEL0; + break; + } + case CAMERA_CONTRAST_LEVEL1: + { + ret = S5K5CAG_CONTRAST_LEVEL1; + break; + } + case CAMERA_CONTRAST_LEVEL2: + { + ret = S5K5CAG_CONTRAST_LEVEL2; + break; + } + case CAMERA_CONTRAST_LEVEL3: + { + ret = S5K5CAG_CONTRAST_LEVEL3; + break; + } + case CAMERA_CONTRAST_LEVEL4: + { + ret = S5K5CAG_CONTRAST_LEVEL4; + break; + } + default: + { + ret = S5K5CAG_CONTRAST_LEVEL0; + break; + } + } + break; + } + case CAMERA_COLOR_EFFECT: + { + switch(value) + { + case CAMERA_COLOR_EFFECT_ANTIQUE: + { + ret = S5K5CAG_COLOR_EFFECT_ANTIQUE; + break; + } + case CAMERA_COLOR_EFFECT_BLUE: + { + ret = S5K5CAG_COLOR_EFFECT_BLUE; + break; + } + case CAMERA_COLOR_EFFECT_GREEN: + { + ret = S5K5CAG_COLOR_EFFECT_GREEN; + break; + } + case CAMERA_COLOR_EFFECT_RED: + { + ret = S5K5CAG_COLOR_EFFECT_RED; + break; + } + default: + { + ret = S5K5CAG_COLOR_EFFECT_NONE; + break; + } + } + break; + default: + { + ret = 0; + break; + } + } + } + + return ret; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/s5k5cag/s5k5cag.h b/src/port_stm32f7/common/bsp_drivers/Components/s5k5cag/s5k5cag.h new file mode 100644 index 00000000..5da02077 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/s5k5cag/s5k5cag.h @@ -0,0 +1,146 @@ +/** + ****************************************************************************** + * @file s5k5cag.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for the s5k5cag.c + * driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __S5K5CAG_H +#define __S5K5CAG_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "../Common/camera.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup s5k5cag + * @{ + */ + +/** @defgroup S5K5CAG_Exported_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup S5K5CAG_Exported_Constants + * @{ + */ +/** + * @brief S5K5CAG ID + */ +#define S5K5CAG_ID ((uint16_t)0x05CA) +/** + * @brief S5K5CAG Registers + */ +#define S5K5CAG_INFO_CHIPID1 ((uint16_t)0x0040) +#define S5K5CAG_INFO_CHIPID2 ((uint16_t)0x0042) +#define S5K5CAG_INFO_SVNVERSION ((uint16_t)0x0048) +#define S5K5CAG_INFO_DATE ((uint16_t)0x004E) + +/** + * @brief S5K5CAG Features Parameters + */ +#define S5K5CAG_BRIGHTNESS_LEVEL0 ((uint16_t)0xFF00) /* Brightness level -2 */ +#define S5K5CAG_BRIGHTNESS_LEVEL1 ((uint16_t)0xFFC0) /* Brightness level -1 */ +#define S5K5CAG_BRIGHTNESS_LEVEL2 ((uint16_t)0x0000) /* Brightness level 0 */ +#define S5K5CAG_BRIGHTNESS_LEVEL3 ((uint16_t)0x0050) /* Brightness level +1 */ +#define S5K5CAG_BRIGHTNESS_LEVEL4 ((uint16_t)0x0080) /* Brightness level +2 */ + +#define S5K5CAG_BLACK_WHITE_BW ((uint16_t)0x0001) /* Black and white effect */ +#define S5K5CAG_BLACK_WHITE_NEGATIVE ((uint16_t)0x0003) /* Negative effect */ +#define S5K5CAG_BLACK_WHITE_BW_NEGATIVE ((uint16_t)0x0002) /* BW and Negative effect */ +#define S5K5CAG_BLACK_WHITE_NORMAL ((uint16_t)0x0000) /* Normal effect */ + +#define S5K5CAG_CONTRAST_LEVEL0 ((uint16_t)0xFF80) /* Contrast level -2 */ +#define S5K5CAG_CONTRAST_LEVEL1 ((uint16_t)0xFFC0) /* Contrast level -1 */ +#define S5K5CAG_CONTRAST_LEVEL2 ((uint16_t)0x0000) /* Contrast level 0 */ +#define S5K5CAG_CONTRAST_LEVEL3 ((uint16_t)0x0050) /* Contrast level -1 */ +#define S5K5CAG_CONTRAST_LEVEL4 ((uint16_t)0x0080) /* Contrast level -2 */ + +#define S5K5CAG_COLOR_EFFECT_NONE ((uint16_t)0x0000) /* No color effect */ +#define S5K5CAG_COLOR_EFFECT_ANTIQUE ((uint16_t)0x0004) /* Antique effect */ +#define S5K5CAG_COLOR_EFFECT_BLUE ((uint16_t)0x0001) /* Blue effect */ +#define S5K5CAG_COLOR_EFFECT_GREEN ((uint16_t)0x0002) /* Green effect */ +#define S5K5CAG_COLOR_EFFECT_RED ((uint16_t)0x0003) /* Red effect */ +/** + * @} + */ + +/** @defgroup S5K5CAG_Exported_Functions + * @{ + */ +void s5k5cag_Init(uint16_t DeviceAddr, uint32_t resolution); +void s5k5cag_Config(uint16_t DeviceAddr, uint32_t feature, uint32_t value, uint32_t BR_value); +uint16_t s5k5cag_ReadID(uint16_t DeviceAddr); + +void CAMERA_IO_Init(void); +void CAMERA_IO_Write(uint8_t addr, uint16_t reg, uint16_t value); +uint16_t CAMERA_IO_Read(uint8_t addr, uint16_t reg); +void CAMERA_Delay(uint32_t delay); + +/* CAMERA driver structure */ +extern CAMERA_DrvTypeDef s5k5cag_drv; +/** + * @} + */ +#ifdef __cplusplus +} +#endif + +#endif /* __S5K5CAG_H */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/st7735/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/st7735/Release_Notes.html new file mode 100644 index 00000000..4c92667a --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/st7735/Release_Notes.html @@ -0,0 +1,322 @@ + + + + + + + + + + + + + + + + + + + Release Notes for ST7735 Component Drivers + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+ +

Release +Notes for ST7735 Component Drivers

+ +

Copyright +2014 STMicroelectronics

+

+
+

 

+ + + + + + +
+ + +

Update History

V1.1.2 +/ 06-June-2017

+ +

Main +Changes

+ + + + + + + + + + +
  • Update comments to be used for PDSC generation

V1.1.1/ 24-November-2014

+ + + + + + + + + + + + + + + + +

Main +Changes

  • st7735.h: change "\" by "/" in the include path to fix compilation issues under +Linux.

V1.1.0/ 22-July-2014

+ + + + + + + + + + + + + + + + +

Main +Changes

  • LCD Component driver update in order to harmonize all LCD controllers Link usage (Change LCD_IO_WriteData to LCD_IO_WriteMultipleData) 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

V1.0.0/ 22-April-2014

+ + + + + + + + + + + + + + + + +

Main +Changes

  • First official release of ST7735 LCD component driver
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

License

+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/st7735/st7735.c b/src/port_stm32f7/common/bsp_drivers/Components/st7735/st7735.c new file mode 100644 index 00000000..3581fb2a --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/st7735/st7735.c @@ -0,0 +1,469 @@ +/** + ****************************************************************************** + * @file st7735.c + * @author MCD Application Team + * @brief This file includes the driver for ST7735 LCD mounted on the Adafruit + * 1.8" TFT LCD shield (reference ID 802). + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "st7735.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup ST7735 + * @brief This file provides a set of functions needed to drive the + * ST7735 LCD. + * @{ + */ + +/** @defgroup ST7735_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @defgroup ST7735_Private_Defines + * @{ + */ + +/** + * @} + */ + +/** @defgroup ST7735_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup ST7735_Private_Variables + * @{ + */ + + +LCD_DrvTypeDef st7735_drv = +{ + st7735_Init, + 0, + st7735_DisplayOn, + st7735_DisplayOff, + st7735_SetCursor, + st7735_WritePixel, + 0, + st7735_SetDisplayWindow, + st7735_DrawHLine, + st7735_DrawVLine, + st7735_GetLcdPixelWidth, + st7735_GetLcdPixelHeight, + st7735_DrawBitmap, +}; + +static uint16_t ArrayRGB[320] = {0}; + +/** +* @} +*/ + +/** @defgroup ST7735_Private_FunctionPrototypes + * @{ + */ + +/** +* @} +*/ + +/** @defgroup ST7735_Private_Functions + * @{ + */ + +/** + * @brief Initialize the ST7735 LCD Component. + * @param None + * @retval None + */ +void st7735_Init(void) +{ + uint8_t data = 0; + + /* Initialize ST7735 low level bus layer -----------------------------------*/ + LCD_IO_Init(); + /* Out of sleep mode, 0 args, no delay */ + st7735_WriteReg(LCD_REG_17, 0x00); + /* Frame rate ctrl - normal mode, 3 args:Rate = fosc/(1x2+40) * (LINE+2C+2D)*/ + LCD_IO_WriteReg(LCD_REG_177); + data = 0x01; + LCD_IO_WriteMultipleData(&data, 1); + data = 0x2C; + LCD_IO_WriteMultipleData(&data, 1); + data = 0x2D; + LCD_IO_WriteMultipleData(&data, 1); + /* Frame rate control - idle mode, 3 args:Rate = fosc/(1x2+40) * (LINE+2C+2D) */ + st7735_WriteReg(LCD_REG_178, 0x01); + st7735_WriteReg(LCD_REG_178, 0x2C); + st7735_WriteReg(LCD_REG_178, 0x2D); + /* Frame rate ctrl - partial mode, 6 args: Dot inversion mode, Line inversion mode */ + st7735_WriteReg(LCD_REG_179, 0x01); + st7735_WriteReg(LCD_REG_179, 0x2C); + st7735_WriteReg(LCD_REG_179, 0x2D); + st7735_WriteReg(LCD_REG_179, 0x01); + st7735_WriteReg(LCD_REG_179, 0x2C); + st7735_WriteReg(LCD_REG_179, 0x2D); + /* Display inversion ctrl, 1 arg, no delay: No inversion */ + st7735_WriteReg(LCD_REG_180, 0x07); + /* Power control, 3 args, no delay: -4.6V , AUTO mode */ + st7735_WriteReg(LCD_REG_192, 0xA2); + st7735_WriteReg(LCD_REG_192, 0x02); + st7735_WriteReg(LCD_REG_192, 0x84); + /* Power control, 1 arg, no delay: VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD */ + st7735_WriteReg(LCD_REG_193, 0xC5); + /* Power control, 2 args, no delay: Opamp current small, Boost frequency */ + st7735_WriteReg(LCD_REG_194, 0x0A); + st7735_WriteReg(LCD_REG_194, 0x00); + /* Power control, 2 args, no delay: BCLK/2, Opamp current small & Medium low */ + st7735_WriteReg(LCD_REG_195, 0x8A); + st7735_WriteReg(LCD_REG_195, 0x2A); + /* Power control, 2 args, no delay */ + st7735_WriteReg(LCD_REG_196, 0x8A); + st7735_WriteReg(LCD_REG_196, 0xEE); + /* Power control, 1 arg, no delay */ + st7735_WriteReg(LCD_REG_197, 0x0E); + /* Don't invert display, no args, no delay */ + LCD_IO_WriteReg(LCD_REG_32); + /* Set color mode, 1 arg, no delay: 16-bit color */ + st7735_WriteReg(LCD_REG_58, 0x05); + /* Column addr set, 4 args, no delay: XSTART = 0, XEND = 127 */ + LCD_IO_WriteReg(LCD_REG_42); + data = 0x00; + LCD_IO_WriteMultipleData(&data, 1); + LCD_IO_WriteMultipleData(&data, 1); + LCD_IO_WriteMultipleData(&data, 1); + data = 0x7F; + LCD_IO_WriteMultipleData(&data, 1); + /* Row addr set, 4 args, no delay: YSTART = 0, YEND = 159 */ + LCD_IO_WriteReg(LCD_REG_43); + data = 0x00; + LCD_IO_WriteMultipleData(&data, 1); + LCD_IO_WriteMultipleData(&data, 1); + LCD_IO_WriteMultipleData(&data, 1); + data = 0x9F; + LCD_IO_WriteMultipleData(&data, 1); + /* Magical unicorn dust, 16 args, no delay */ + st7735_WriteReg(LCD_REG_224, 0x02); + st7735_WriteReg(LCD_REG_224, 0x1c); + st7735_WriteReg(LCD_REG_224, 0x07); + st7735_WriteReg(LCD_REG_224, 0x12); + st7735_WriteReg(LCD_REG_224, 0x37); + st7735_WriteReg(LCD_REG_224, 0x32); + st7735_WriteReg(LCD_REG_224, 0x29); + st7735_WriteReg(LCD_REG_224, 0x2d); + st7735_WriteReg(LCD_REG_224, 0x29); + st7735_WriteReg(LCD_REG_224, 0x25); + st7735_WriteReg(LCD_REG_224, 0x2B); + st7735_WriteReg(LCD_REG_224, 0x39); + st7735_WriteReg(LCD_REG_224, 0x00); + st7735_WriteReg(LCD_REG_224, 0x01); + st7735_WriteReg(LCD_REG_224, 0x03); + st7735_WriteReg(LCD_REG_224, 0x10); + /* Sparkles and rainbows, 16 args, no delay */ + st7735_WriteReg(LCD_REG_225, 0x03); + st7735_WriteReg(LCD_REG_225, 0x1d); + st7735_WriteReg(LCD_REG_225, 0x07); + st7735_WriteReg(LCD_REG_225, 0x06); + st7735_WriteReg(LCD_REG_225, 0x2E); + st7735_WriteReg(LCD_REG_225, 0x2C); + st7735_WriteReg(LCD_REG_225, 0x29); + st7735_WriteReg(LCD_REG_225, 0x2D); + st7735_WriteReg(LCD_REG_225, 0x2E); + st7735_WriteReg(LCD_REG_225, 0x2E); + st7735_WriteReg(LCD_REG_225, 0x37); + st7735_WriteReg(LCD_REG_225, 0x3F); + st7735_WriteReg(LCD_REG_225, 0x00); + st7735_WriteReg(LCD_REG_225, 0x00); + st7735_WriteReg(LCD_REG_225, 0x02); + st7735_WriteReg(LCD_REG_225, 0x10); + /* Normal display on, no args, no delay */ + st7735_WriteReg(LCD_REG_19, 0x00); + /* Main screen turn on, no delay */ + st7735_WriteReg(LCD_REG_41, 0x00); + /* Memory access control: MY = 1, MX = 1, MV = 0, ML = 0 */ + st7735_WriteReg(LCD_REG_54, 0xC0); +} + +/** + * @brief Enables the Display. + * @param None + * @retval None + */ +void st7735_DisplayOn(void) +{ + uint8_t data = 0; + LCD_IO_WriteReg(LCD_REG_19); + LCD_Delay(10); + LCD_IO_WriteReg(LCD_REG_41); + LCD_Delay(10); + LCD_IO_WriteReg(LCD_REG_54); + data = 0xC0; + LCD_IO_WriteMultipleData(&data, 1); +} + +/** + * @brief Disables the Display. + * @param None + * @retval None + */ +void st7735_DisplayOff(void) +{ + uint8_t data = 0; + LCD_IO_WriteReg(LCD_REG_19); + LCD_Delay(10); + LCD_IO_WriteReg(LCD_REG_40); + LCD_Delay(10); + LCD_IO_WriteReg(LCD_REG_54); + data = 0xC0; + LCD_IO_WriteMultipleData(&data, 1); +} + +/** + * @brief Sets Cursor position. + * @param Xpos: specifies the X position. + * @param Ypos: specifies the Y position. + * @retval None + */ +void st7735_SetCursor(uint16_t Xpos, uint16_t Ypos) +{ + uint8_t data = 0; + LCD_IO_WriteReg(LCD_REG_42); + data = (Xpos) >> 8; + LCD_IO_WriteMultipleData(&data, 1); + data = (Xpos) & 0xFF; + LCD_IO_WriteMultipleData(&data, 1); + LCD_IO_WriteReg(LCD_REG_43); + data = (Ypos) >> 8; + LCD_IO_WriteMultipleData(&data, 1); + data = (Ypos) & 0xFF; + LCD_IO_WriteMultipleData(&data, 1); + LCD_IO_WriteReg(LCD_REG_44); +} + +/** + * @brief Writes pixel. + * @param Xpos: specifies the X position. + * @param Ypos: specifies the Y position. + * @param RGBCode: the RGB pixel color + * @retval None + */ +void st7735_WritePixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGBCode) +{ + uint8_t data = 0; + if((Xpos >= ST7735_LCD_PIXEL_WIDTH) || (Ypos >= ST7735_LCD_PIXEL_HEIGHT)) + { + return; + } + + /* Set Cursor */ + st7735_SetCursor(Xpos, Ypos); + + data = RGBCode >> 8; + LCD_IO_WriteMultipleData(&data, 1); + data = RGBCode; + LCD_IO_WriteMultipleData(&data, 1); +} + + +/** + * @brief Writes to the selected LCD register. + * @param LCDReg: Address of the selected register. + * @param LCDRegValue: value to write to the selected register. + * @retval None + */ +void st7735_WriteReg(uint8_t LCDReg, uint8_t LCDRegValue) +{ + LCD_IO_WriteReg(LCDReg); + LCD_IO_WriteMultipleData(&LCDRegValue, 1); +} + +/** + * @brief Sets a display window + * @param Xpos: specifies the X bottom left position. + * @param Ypos: specifies the Y bottom left position. + * @param Height: display window height. + * @param Width: display window width. + * @retval None + */ +void st7735_SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + uint8_t data = 0; + /* Column addr set, 4 args, no delay: XSTART = Xpos, XEND = (Xpos + Width - 1) */ + LCD_IO_WriteReg(LCD_REG_42); + data = (Xpos) >> 8; + LCD_IO_WriteMultipleData(&data, 1); + data = (Xpos) & 0xFF; + LCD_IO_WriteMultipleData(&data, 1); + data = (Xpos + Width - 1) >> 8; + LCD_IO_WriteMultipleData(&data, 1); + data = (Xpos + Width - 1) & 0xFF; + LCD_IO_WriteMultipleData(&data, 1); + /* Row addr set, 4 args, no delay: YSTART = Ypos, YEND = (Ypos + Height - 1) */ + LCD_IO_WriteReg(LCD_REG_43); + data = (Ypos) >> 8; + LCD_IO_WriteMultipleData(&data, 1); + data = (Ypos) & 0xFF; + LCD_IO_WriteMultipleData(&data, 1); + data = (Ypos + Height - 1) >> 8; + LCD_IO_WriteMultipleData(&data, 1); + data = (Ypos + Height - 1) & 0xFF; + LCD_IO_WriteMultipleData(&data, 1); +} + +/** + * @brief Draws horizontal line. + * @param RGBCode: Specifies the RGB color + * @param Xpos: specifies the X position. + * @param Ypos: specifies the Y position. + * @param Length: specifies the line length. + * @retval None + */ +void st7735_DrawHLine(uint16_t RGBCode, uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint8_t counter = 0; + + if(Xpos + Length > ST7735_LCD_PIXEL_WIDTH) return; + + /* Set Cursor */ + st7735_SetCursor(Xpos, Ypos); + + for(counter = 0; counter < Length; counter++) + { + ArrayRGB[counter] = RGBCode; + } + LCD_IO_WriteMultipleData((uint8_t*)&ArrayRGB[0], Length * 2); +} + +/** + * @brief Draws vertical line. + * @param RGBCode: Specifies the RGB color + * @param Xpos: specifies the X position. + * @param Ypos: specifies the Y position. + * @param Length: specifies the line length. + * @retval None + */ +void st7735_DrawVLine(uint16_t RGBCode, uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint8_t counter = 0; + + if(Ypos + Length > ST7735_LCD_PIXEL_HEIGHT) return; + for(counter = 0; counter < Length; counter++) + { + st7735_WritePixel(Xpos, Ypos + counter, RGBCode); + } +} + +/** + * @brief Gets the LCD pixel Width. + * @param None + * @retval The Lcd Pixel Width + */ +uint16_t st7735_GetLcdPixelWidth(void) +{ + return ST7735_LCD_PIXEL_WIDTH; +} + +/** + * @brief Gets the LCD pixel Height. + * @param None + * @retval The Lcd Pixel Height + */ +uint16_t st7735_GetLcdPixelHeight(void) +{ + return ST7735_LCD_PIXEL_HEIGHT; +} + +/** + * @brief Displays a bitmap picture loaded in the internal Flash. + * @param BmpAddress: Bmp picture address in the internal Flash. + * @retval None + */ +void st7735_DrawBitmap(uint16_t Xpos, uint16_t Ypos, uint8_t *pbmp) +{ + uint32_t index = 0, size = 0; + + /* Read bitmap size */ + size = *(volatile uint16_t *) (pbmp + 2); + size |= (*(volatile uint16_t *) (pbmp + 4)) << 16; + /* Get bitmap data address offset */ + index = *(volatile uint16_t *) (pbmp + 10); + index |= (*(volatile uint16_t *) (pbmp + 12)) << 16; + size = (size - index)/2; + pbmp += index; + + /* Set GRAM write direction and BGR = 0 */ + /* Memory access control: MY = 0, MX = 1, MV = 0, ML = 0 */ + st7735_WriteReg(LCD_REG_54, 0x40); + + /* Set Cursor */ + st7735_SetCursor(Xpos, Ypos); + + LCD_IO_WriteMultipleData((uint8_t*)pbmp, size*2); + + /* Set GRAM write direction and BGR = 0 */ + /* Memory access control: MY = 1, MX = 1, MV = 0, ML = 0 */ + st7735_WriteReg(LCD_REG_54, 0xC0); +} + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/** +* @} +*/ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/port_stm32f7/common/bsp_drivers/Components/st7735/st7735.h b/src/port_stm32f7/common/bsp_drivers/Components/st7735/st7735.h new file mode 100644 index 00000000..ec523cbc --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/st7735/st7735.h @@ -0,0 +1,212 @@ +/** + ****************************************************************************** + * @file st7735.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for the st7735.c + * driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __ST7735_H +#define __ST7735_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "../Common/lcd.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup ST7735 + * @{ + */ + +/** @defgroup ST7735_Exported_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup ST7735_Exported_Constants + * @{ + */ + +/** + * @brief ST7735 Size + */ +#define ST7735_LCD_PIXEL_WIDTH ((uint16_t)128) +#define ST7735_LCD_PIXEL_HEIGHT ((uint16_t)160) + +/** + * @brief ST7735 Registers + */ +#define LCD_REG_0 0x00 /* No Operation: NOP */ +#define LCD_REG_1 0x01 /* Software reset: SWRESET */ +#define LCD_REG_4 0x04 /* Read Display ID: RDDID */ +#define LCD_REG_9 0x09 /* Read Display Statu: RDDST */ +#define LCD_REG_10 0x0A /* Read Display Power: RDDPM */ +#define LCD_REG_11 0x0B /* Read Display: RDDMADCTL */ +#define LCD_REG_12 0x0C /* Read Display Pixel: RDDCOLMOD */ +#define LCD_REG_13 0x0D /* Read Display Image: RDDIM */ +#define LCD_REG_14 0x0E /* Read Display Signal: RDDSM */ +#define LCD_REG_16 0x10 /* Sleep in & booster off: SLPIN */ +#define LCD_REG_17 0x11 /* Sleep out & booster on: SLPOUT */ +#define LCD_REG_18 0x12 /* Partial mode on: PTLON */ +#define LCD_REG_19 0x13 /* Partial off (Normal): NORON */ +#define LCD_REG_32 0x20 /* Display inversion off: INVOFF */ +#define LCD_REG_33 0x21 /* Display inversion on: INVON */ +#define LCD_REG_38 0x26 /* Gamma curve select: GAMSET */ +#define LCD_REG_40 0x28 /* Display off: DISPOFF */ +#define LCD_REG_41 0x29 /* Display on: DISPON */ +#define LCD_REG_42 0x2A /* Column address set: CASET */ +#define LCD_REG_43 0x2B /* Row address set: RASET */ +#define LCD_REG_44 0x2C /* Memory write: RAMWR */ +#define LCD_REG_45 0x2D /* LUT for 4k,65k,262k color: RGBSET */ +#define LCD_REG_46 0x2E /* Memory read: RAMRD*/ +#define LCD_REG_48 0x30 /* Partial start/end address set: PTLAR */ +#define LCD_REG_52 0x34 /* Tearing effect line off: TEOFF */ +#define LCD_REG_53 0x35 /* Tearing effect mode set & on: TEON */ +#define LCD_REG_54 0x36 /* Memory data access control: MADCTL */ +#define LCD_REG_56 0x38 /* Idle mode off: IDMOFF */ +#define LCD_REG_57 0x39 /* Idle mode on: IDMON */ +#define LCD_REG_58 0x3A /* Interface pixel format: COLMOD */ +#define LCD_REG_177 0xB1 /* In normal mode (Full colors): FRMCTR1 */ +#define LCD_REG_178 0xB2 /* In Idle mode (8-colors): FRMCTR2 */ +#define LCD_REG_179 0xB3 /* In partial mode + Full colors: FRMCTR3 */ +#define LCD_REG_180 0xB4 /* Display inversion control: INVCTR */ +#define LCD_REG_192 0xC0 /* Power control setting: PWCTR1 */ +#define LCD_REG_193 0xC1 /* Power control setting: PWCTR2 */ +#define LCD_REG_194 0xC2 /* In normal mode (Full colors): PWCTR3 */ +#define LCD_REG_195 0xC3 /* In Idle mode (8-colors): PWCTR4 */ +#define LCD_REG_196 0xC4 /* In partial mode + Full colors: PWCTR5 */ +#define LCD_REG_197 0xC5 /* VCOM control 1: VMCTR1 */ +#define LCD_REG_199 0xC7 /* Set VCOM offset control: VMOFCTR */ +#define LCD_REG_209 0xD1 /* Set LCM version code: WRID2 */ +#define LCD_REG_210 0xD2 /* Customer Project code: WRID3 */ +#define LCD_REG_217 0xD9 /* NVM control status: NVCTR1 */ +#define LCD_REG_218 0xDA /* Read ID1: RDID1 */ +#define LCD_REG_219 0xDB /* Read ID2: RDID2 */ +#define LCD_REG_220 0xDC /* Read ID3: RDID3 */ +#define LCD_REG_222 0xDE /* NVM Read Command: NVCTR2 */ +#define LCD_REG_223 0xDF /* NVM Write Command: NVCTR3 */ +#define LCD_REG_224 0xE0 /* Set Gamma adjustment (+ polarity): GAMCTRP1 */ +#define LCD_REG_225 0xE1 /* Set Gamma adjustment (- polarity): GAMCTRN1 */ + +/** + * @brief LCD Lines depending on the chosen fonts. + */ +#define LCD_LINE_0 LINE(0) +#define LCD_LINE_1 LINE(1) +#define LCD_LINE_2 LINE(2) +#define LCD_LINE_3 LINE(3) +#define LCD_LINE_4 LINE(4) +#define LCD_LINE_5 LINE(5) +#define LCD_LINE_6 LINE(6) +#define LCD_LINE_7 LINE(7) +#define LCD_LINE_8 LINE(8) +#define LCD_LINE_9 LINE(9) +#define LCD_LINE_10 LINE(10) +#define LCD_LINE_11 LINE(11) +#define LCD_LINE_12 LINE(12) +#define LCD_LINE_13 LINE(13) +#define LCD_LINE_14 LINE(14) +#define LCD_LINE_15 LINE(15) +#define LCD_LINE_16 LINE(16) +#define LCD_LINE_17 LINE(17) +#define LCD_LINE_18 LINE(18) +#define LCD_LINE_19 LINE(19) + +/** + * @} + */ + +/** @defgroup ADAFRUIT_SPI_LCD_Exported_Functions + * @{ + */ +void st7735_Init(void); +uint16_t st7735_ReadID(void); + +void st7735_DisplayOn(void); +void st7735_DisplayOff(void); +void st7735_SetCursor(uint16_t Xpos, uint16_t Ypos); +void st7735_WritePixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGBCode); +void st7735_WriteReg(uint8_t LCDReg, uint8_t LCDRegValue); +uint8_t st7735_ReadReg(uint8_t LCDReg); + +void st7735_SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void st7735_DrawHLine(uint16_t RGBCode, uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void st7735_DrawVLine(uint16_t RGBCode, uint16_t Xpos, uint16_t Ypos, uint16_t Length); + +uint16_t st7735_GetLcdPixelWidth(void); +uint16_t st7735_GetLcdPixelHeight(void); +void st7735_DrawBitmap(uint16_t Xpos, uint16_t Ypos, uint8_t *pbmp); + +/* LCD driver structure */ +extern LCD_DrvTypeDef st7735_drv; + +/* LCD IO functions */ +void LCD_IO_Init(void); +void LCD_IO_WriteMultipleData(uint8_t *pData, uint32_t Size); +void LCD_IO_WriteReg(uint8_t Reg); +void LCD_Delay(uint32_t delay); +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ST7735_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/st7789h2/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/st7789h2/Release_Notes.html new file mode 100644 index 00000000..8c939bbe --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/st7789h2/Release_Notes.html @@ -0,0 +1,330 @@ + + + +Release Note for ST7789H2 component Driver + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for ST7789H2 Component Driver

+

Copyright +2016 STMicroelectronics

+

+
+

 

+ + + + + + +
+ + +

Update History

V1.1.2 +/ 05-June-2017

+ +

Main +Changes

+ + + + + + + + + + +
  • Update comments to be used for PDSC generation

V1.1.1 / 29-December-2016

+

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • st7789h2.c/.h:
    • Change "\" by "/" in the include path to fix compilation issue under linux
      +
    +
+ +

V1.1.0 / 22-December-2016

+

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • st7789h2.c/.h:
  • +
      +
    • Add 180°  orientation support
      + +
    • +
    + +
+

V1.0.1 / 04-July-2016

+

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • st7789h2.c:
    • Update ST7789H2_DisplayOn()
+

V1.0.0 / 04-May-2016

+

Main +Changes

+
  • First official release of ST7789H2 LCD component driver
+

License

+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/st7789h2/st7789h2.c b/src/port_stm32f7/common/bsp_drivers/Components/st7789h2/st7789h2.c new file mode 100644 index 00000000..19f17f34 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/st7789h2/st7789h2.c @@ -0,0 +1,723 @@ +/** + ****************************************************************************** + * @file st7789h2.c + * @author MCD Application Team + * @brief This file includes the LCD driver for st7789h2 LCD. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "st7789h2.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @defgroup ST7789H2 + * @brief This file provides a set of functions needed to drive the + * FRIDA FRD154BP2901 LCD. + * @{ + */ + +/** @defgroup ST7789H2_Private_TypesDefinitions ST7789H2 Private TypesDefinitions + * @{ + */ +typedef struct { + uint8_t red; + uint8_t green; + uint8_t blue; +} ST7789H2_Rgb888; + +/** + * @} + */ + +/** @defgroup ST7789H2_Private_Defines ST7789H2 Private Defines + * @{ + */ + +/** + * @} + */ + +/** @defgroup ST7789H2_Private_Macros ST7789H2 Private Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup ST7789H2_Private_Variables ST7789H2 Private Variables + * @{ + */ +LCD_DrvTypeDef ST7789H2_drv = +{ + ST7789H2_Init, + ST7789H2_ReadID, + ST7789H2_DisplayOn, + ST7789H2_DisplayOff, + ST7789H2_SetCursor, + ST7789H2_WritePixel, + ST7789H2_ReadPixel, + ST7789H2_SetDisplayWindow, + ST7789H2_DrawHLine, + ST7789H2_DrawVLine, + ST7789H2_GetLcdPixelWidth, + ST7789H2_GetLcdPixelHeight, + ST7789H2_DrawBitmap, + ST7789H2_DrawRGBImage, +}; + +static uint16_t WindowsXstart = 0; +static uint16_t WindowsYstart = 0; +static uint16_t WindowsXend = ST7789H2_LCD_PIXEL_WIDTH-1; +static uint16_t WindowsYend = ST7789H2_LCD_PIXEL_HEIGHT-1; +/** + * @} + */ + +/** @defgroup ST7789H2_Private_FunctionPrototypes ST7789H2 Private FunctionPrototypes + * @{ + */ +static ST7789H2_Rgb888 ST7789H2_ReadPixel_rgb888(uint16_t Xpos, uint16_t Ypos); +static void ST7789H2_DrawRGBHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint8_t *pdata); + +/** + * @} + */ + +/** @defgroup ST7789H2_Private_Functions ST7789H2 Private Functions + * @{ + */ + +/** + * @brief Initialize the st7789h2 LCD Component. + * @param None + * @retval None + */ +void ST7789H2_Init(void) +{ + uint8_t parameter[14]; + + /* Initialize st7789h2 low level bus layer ----------------------------------*/ + LCD_IO_Init(); + /* Sleep In Command */ + ST7789H2_WriteReg(ST7789H2_SLEEP_IN, (uint8_t*)NULL, 0); + /* Wait for 10ms */ + LCD_IO_Delay(10); + + /* SW Reset Command */ + ST7789H2_WriteReg(0x01, (uint8_t*)NULL, 0); + /* Wait for 200ms */ + LCD_IO_Delay(200); + + /* Sleep Out Command */ + ST7789H2_WriteReg(ST7789H2_SLEEP_OUT, (uint8_t*)NULL, 0); + /* Wait for 120ms */ + LCD_IO_Delay(120); + + /* Normal display for Driver Down side */ + parameter[0] = 0x00; + ST7789H2_WriteReg(ST7789H2_NORMAL_DISPLAY, parameter, 1); + + /* Color mode 16bits/pixel */ + parameter[0] = 0x05; + ST7789H2_WriteReg(ST7789H2_COLOR_MODE, parameter, 1); + + /* Display inversion On */ + ST7789H2_WriteReg(ST7789H2_DISPLAY_INVERSION, (uint8_t*)NULL, 0); + + /* Set Column address CASET */ + parameter[0] = 0x00; + parameter[1] = 0x00; + parameter[2] = 0x00; + parameter[3] = 0xEF; + ST7789H2_WriteReg(ST7789H2_CASET, parameter, 4); + /* Set Row address RASET */ + parameter[0] = 0x00; + parameter[1] = 0x00; + parameter[2] = 0x00; + parameter[3] = 0xEF; + ST7789H2_WriteReg(ST7789H2_RASET, parameter, 4); + + /*--------------- ST7789H2 Frame rate setting -------------------------------*/ + /* PORCH control setting */ + parameter[0] = 0x0C; + parameter[1] = 0x0C; + parameter[2] = 0x00; + parameter[3] = 0x33; + parameter[4] = 0x33; + ST7789H2_WriteReg(ST7789H2_PORCH_CTRL, parameter, 5); + + /* GATE control setting */ + parameter[0] = 0x35; + ST7789H2_WriteReg(ST7789H2_GATE_CTRL, parameter, 1); + + /*--------------- ST7789H2 Power setting ------------------------------------*/ + /* VCOM setting */ + parameter[0] = 0x1F; + ST7789H2_WriteReg(ST7789H2_VCOM_SET, parameter, 1); + + /* LCM Control setting */ + parameter[0] = 0x2C; + ST7789H2_WriteReg(ST7789H2_LCM_CTRL, parameter, 1); + + /* VDV and VRH Command Enable */ + parameter[0] = 0x01; + parameter[1] = 0xC3; + ST7789H2_WriteReg(ST7789H2_VDV_VRH_EN, parameter, 2); + + /* VDV Set */ + parameter[0] = 0x20; + ST7789H2_WriteReg(ST7789H2_VDV_SET, parameter, 1); + + /* Frame Rate Control in normal mode */ + parameter[0] = 0x0F; + ST7789H2_WriteReg(ST7789H2_FR_CTRL, parameter, 1); + + /* Power Control */ + parameter[0] = 0xA4; + parameter[1] = 0xA1; + ST7789H2_WriteReg(ST7789H2_POWER_CTRL, parameter, 1); + + /*--------------- ST7789H2 Gamma setting ------------------------------------*/ + /* Positive Voltage Gamma Control */ + parameter[0] = 0xD0; + parameter[1] = 0x08; + parameter[2] = 0x11; + parameter[3] = 0x08; + parameter[4] = 0x0C; + parameter[5] = 0x15; + parameter[6] = 0x39; + parameter[7] = 0x33; + parameter[8] = 0x50; + parameter[9] = 0x36; + parameter[10] = 0x13; + parameter[11] = 0x14; + parameter[12] = 0x29; + parameter[13] = 0x2D; + ST7789H2_WriteReg(ST7789H2_PV_GAMMA_CTRL, parameter, 14); + + /* Negative Voltage Gamma Control */ + parameter[0] = 0xD0; + parameter[1] = 0x08; + parameter[2] = 0x10; + parameter[3] = 0x08; + parameter[4] = 0x06; + parameter[5] = 0x06; + parameter[6] = 0x39; + parameter[7] = 0x44; + parameter[8] = 0x51; + parameter[9] = 0x0B; + parameter[10] = 0x16; + parameter[11] = 0x14; + parameter[12] = 0x2F; + parameter[13] = 0x31; + ST7789H2_WriteReg(ST7789H2_NV_GAMMA_CTRL, parameter, 14); + + /* Display ON command */ + ST7789H2_DisplayOn(); + + /* Tearing Effect Line On: Option (00h:VSYNC Interface OFF, 01h:VSYNC Interface ON) */ + parameter[0] = 0x00; + ST7789H2_WriteReg(ST7789H2_TEARING_EFFECT, parameter, 1); + +} + +/** + * @brief Set the Display Orientation. + * @param orientation: ST7789H2_ORIENTATION_PORTRAIT, ST7789H2_ORIENTATION_LANDSCAPE + * or ST7789H2_ORIENTATION_LANDSCAPE_ROT180 + * @retval None + */ +void ST7789H2_SetOrientation(uint32_t orientation) +{ + uint8_t parameter[6]; + + if(orientation == ST7789H2_ORIENTATION_LANDSCAPE) + { + parameter[0] = 0x00; + } + else if(orientation == ST7789H2_ORIENTATION_LANDSCAPE_ROT180) + { + /* Vertical Scrolling Definition */ + /* TFA describes the Top Fixed Area */ + parameter[0] = 0x00; + parameter[1] = 0x00; + /* VSA describes the height of the Vertical Scrolling Area */ + parameter[2] = 0x01; + parameter[3] = 0xF0; + /* BFA describes the Bottom Fixed Area */ + parameter[4] = 0x00; + parameter[5] = 0x00; + ST7789H2_WriteReg(ST7789H2_VSCRDEF, parameter, 6); + + /* Vertical Scroll Start Address of RAM */ + /* GRAM row nbr (320) - Display row nbr (240) = 80 = 0x50 */ + parameter[0] = 0x00; + parameter[1] = 0x50; + ST7789H2_WriteReg(ST7789H2_VSCSAD, parameter, 2); + + parameter[0] = 0xC0; + } + else + { + parameter[0] = 0x60; + } + ST7789H2_WriteReg(ST7789H2_NORMAL_DISPLAY, parameter, 1); +} + +/** + * @brief Enables the Display. + * @param None + * @retval None + */ +void ST7789H2_DisplayOn(void) +{ + /* Display ON command */ + ST7789H2_WriteReg(ST7789H2_DISPLAY_ON, (uint8_t*)NULL, 0); + + /* Sleep Out command */ + ST7789H2_WriteReg(ST7789H2_SLEEP_OUT, (uint8_t*)NULL, 0); +} + +/** + * @brief Disables the Display. + * @param None + * @retval None + */ +void ST7789H2_DisplayOff(void) +{ + uint8_t parameter[1]; + parameter[0] = 0xFE; + /* Display OFF command */ + ST7789H2_WriteReg(ST7789H2_DISPLAY_OFF, parameter, 1); + /* Sleep In Command */ + ST7789H2_WriteReg(ST7789H2_SLEEP_IN, (uint8_t*)NULL, 0); + /* Wait for 10ms */ + LCD_IO_Delay(10); +} + +/** + * @brief Get the LCD pixel Width. + * @param None + * @retval The Lcd Pixel Width + */ +uint16_t ST7789H2_GetLcdPixelWidth(void) +{ + return (uint16_t)ST7789H2_LCD_PIXEL_WIDTH; +} + +/** + * @brief Get the LCD pixel Height. + * @param None + * @retval The Lcd Pixel Height + */ +uint16_t ST7789H2_GetLcdPixelHeight(void) +{ + return (uint16_t)ST7789H2_LCD_PIXEL_HEIGHT; +} + +/** + * @brief Get the st7789h2 ID. + * @param None + * @retval The st7789h2 ID + */ +uint16_t ST7789H2_ReadID(void) +{ + LCD_IO_Init(); + + return ST7789H2_ReadReg(ST7789H2_LCD_ID); +} + +/** + * @brief Set Cursor position. + * @param Xpos: specifies the X position. + * @param Ypos: specifies the Y position. + * @retval None + */ +void ST7789H2_SetCursor(uint16_t Xpos, uint16_t Ypos) +{ + uint8_t parameter[4]; + /* CASET: Comumn Addrses Set */ + parameter[0] = 0x00; + parameter[1] = 0x00 + Xpos; + parameter[2] = 0x00; + parameter[3] = 0xEF + Xpos; + ST7789H2_WriteReg(ST7789H2_CASET, parameter, 4); + /* RASET: Row Addrses Set */ + parameter[0] = 0x00; + parameter[1] = 0x00 + Ypos; + parameter[2] = 0x00; + parameter[3] = 0xEF + Ypos; + ST7789H2_WriteReg(ST7789H2_RASET, parameter, 4); +} + +/** + * @brief Write pixel. + * @param Xpos: specifies the X position. + * @param Ypos: specifies the Y position. + * @param RGBCode: the RGB pixel color in RGB565 format + * @retval None + */ +void ST7789H2_WritePixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGBCode) +{ + /* Set Cursor */ + ST7789H2_SetCursor(Xpos, Ypos); + + /* Prepare to write to LCD RAM */ + ST7789H2_WriteReg(ST7789H2_WRITE_RAM, (uint8_t*)NULL, 0); /* RAM write data command */ + + /* Write RAM data */ + LCD_IO_WriteData(RGBCode); +} + +/** + * @brief Read pixel. + * @param Xpos: specifies the X position. + * @param Ypos: specifies the Y position. + * @retval The RGB pixel color in RGB565 format + */ +uint16_t ST7789H2_ReadPixel(uint16_t Xpos, uint16_t Ypos) +{ + ST7789H2_Rgb888 rgb888; + uint8_t r, g, b; + uint16_t rgb565; + + /* Set Cursor */ + ST7789H2_SetCursor(Xpos, Ypos); + + /* Read RGB888 data from LCD RAM */ + rgb888 = ST7789H2_ReadPixel_rgb888(Xpos, Ypos); + + /* Convert RGB888 to RGB565 */ + r = ((rgb888.red & 0xF8) >> 3); /* Extract the red component 5 most significant bits */ + g = ((rgb888.green & 0xFC) >> 2); /* Extract the green component 6 most significant bits */ + b = ((rgb888.blue & 0xF8) >> 3); /* Extract the blue component 5 most significant bits */ + + rgb565 = ((uint16_t)(r) << 11) + ((uint16_t)(g) << 5) + ((uint16_t)(b) << 0); + + return (rgb565); +} + +/** + * @brief Writes to the selected LCD register. + * @param Command: command value (or register address as named in st7789h2 doc). + * @param Parameters: pointer on parameters value (if command uses one or several parameters). + * @param NbParameters: number of command parameters (0 if no parameter) + * @retval None + */ +void ST7789H2_WriteReg(uint8_t Command, uint8_t *Parameters, uint8_t NbParameters) +{ + uint8_t i; + + /* Send command */ + LCD_IO_WriteReg(Command); + + /* Send command's parameters if any */ + for (i=0; i Ypos; posY--) /* In BMP files the line order is inverted */ + { + /* Set Cursor */ + ST7789H2_SetCursor(Xpos, posY - 1); + + /* Draw one line of the picture */ + ST7789H2_DrawRGBHLine(Xpos, posY - 1, Xsize, (pbmp + (nb_line * Xsize * 2))); + nb_line++; + } +} + +/** + * @brief Displays picture. + * @param pdata: picture address. + * @param Xpos: Image X position in the LCD + * @param Ypos: Image Y position in the LCD + * @param Xsize: Image X size in the LCD + * @param Ysize: Image Y size in the LCD + * @retval None + */ +void ST7789H2_DrawRGBImage(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint16_t Ysize, uint8_t *pdata) +{ + uint32_t posY; + uint32_t nb_line = 0; + + for (posY = Ypos; posY < (Ypos + Ysize); posY ++) + { + /* Set Cursor */ + ST7789H2_SetCursor(Xpos, posY); + + /* Draw one line of the picture */ + ST7789H2_DrawRGBHLine(Xpos, posY, Xsize, (pdata + (nb_line * Xsize * 2))); + nb_line++; + } +} + + +/****************************************************************************** + Static Functions +*******************************************************************************/ + +/** + * @brief Read pixel from LCD RAM in RGB888 format + * @param Xpos: specifies the X position. + * @param Ypos: specifies the Y position. + * @retval Each RGB pixel color components in a structure + */ +static ST7789H2_Rgb888 ST7789H2_ReadPixel_rgb888(uint16_t Xpos, uint16_t Ypos) +{ + ST7789H2_Rgb888 rgb888; + uint16_t rgb888_part1, rgb888_part2; + + /* In LCD RAM, pixels are 24 bits packed and read with 16 bits access + * Here is the pixels components arrangement in memory : + * bits: 15 14 13 12 11 10 09 08 | 07 06 05 04 03 02 01 00 + * address 0 : red pixel 0 X X | green pixel 0 X X + * address 1 : blue pixel 0 X X | red pixel 1 X X + * address 2 : green pixel 1 X X | blue pixel 1 X X + */ + + /* Set Cursor */ + ST7789H2_SetCursor(Xpos, Ypos); + /* Prepare to read LCD RAM */ + ST7789H2_WriteReg(ST7789H2_READ_RAM, (uint8_t*)NULL, 0); /* RAM read data command */ + /* Dummy read */ + LCD_IO_ReadData(); + /* Read first part of the RGB888 data */ + rgb888_part1 = LCD_IO_ReadData(); + /* Read first part of the RGB888 data */ + rgb888_part2 = LCD_IO_ReadData(); + + /* red component */ + rgb888.red = (rgb888_part1 & 0xFC00) >> 8; + /* green component */ + rgb888.green = (rgb888_part1 & 0x00FC) >> 0; + /* blue component */ + rgb888.blue = (rgb888_part2 & 0xFC00) >> 8; + + return rgb888; +} + + +/** + * @brief Displays a single picture line. + * @param pdata: picture address. + * @param Xpos: Image X position in the LCD + * @param Ypos: Image Y position in the LCD + * @param Xsize: Image X size in the LCD + * @retval None + */ +static void ST7789H2_DrawRGBHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint8_t *pdata) +{ + uint32_t i = 0; + uint32_t posX; + uint16_t *rgb565 = (uint16_t*)pdata; + + /* Prepare to write to LCD RAM */ + ST7789H2_WriteReg(ST7789H2_WRITE_RAM, (uint8_t*)NULL, 0); /* RAM write data command */ + + for (posX = Xpos; posX < (Xsize + Xpos); posX++) + { + if ((posX >= WindowsXstart) && (Ypos >= WindowsYstart) && /* Check we are in the defined window */ + (posX <= WindowsXend) && (Ypos <= WindowsYend)) + { + if (posX != (Xsize + Xpos)) /* When writing last pixel when size is odd, the third part is not written */ + { + LCD_IO_WriteData(rgb565[i]); + } + i++; + } + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/st7789h2/st7789h2.h b/src/port_stm32f7/common/bsp_drivers/Components/st7789h2/st7789h2.h new file mode 100644 index 00000000..271e30db --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/st7789h2/st7789h2.h @@ -0,0 +1,186 @@ +/** + ****************************************************************************** + * @file st7789h2.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for the st7789h2.c + * driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __ST7789H2_H +#define __ST7789H2_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include +#include "../Common/lcd.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup ST7789H2 + * @{ + */ + +/** @defgroup ST7789H2_Exported_Types ST7789H2 Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup ST7789H2_Exported_Constants ST7789H2 Exported Constants + * @{ + */ +/** + * @brief ST7789H2 ID + */ +#define ST7789H2_ID 0x85 + +/** + * @brief ST7789H2 Size + */ +#define ST7789H2_LCD_PIXEL_WIDTH ((uint16_t)240) +#define ST7789H2_LCD_PIXEL_HEIGHT ((uint16_t)240) + +/** + * @brief LCD_OrientationTypeDef + * Possible values of Display Orientation + */ +#define ST7789H2_ORIENTATION_PORTRAIT ((uint32_t)0x00) /* Portrait orientation choice of LCD screen */ +#define ST7789H2_ORIENTATION_LANDSCAPE ((uint32_t)0x01) /* Landscape orientation choice of LCD screen */ +#define ST7789H2_ORIENTATION_LANDSCAPE_ROT180 ((uint32_t)0x02) /* Landscape rotated 180° orientation choice of LCD screen */ + +/** + * @brief ST7789H2 Registers + */ +#define ST7789H2_LCD_ID 0x04 +#define ST7789H2_SLEEP_IN 0x10 +#define ST7789H2_SLEEP_OUT 0x11 +#define ST7789H2_PARTIAL_DISPLAY 0x12 +#define ST7789H2_DISPLAY_INVERSION 0x21 +#define ST7789H2_DISPLAY_ON 0x29 +#define ST7789H2_WRITE_RAM 0x2C +#define ST7789H2_READ_RAM 0x2E +#define ST7789H2_CASET 0x2A +#define ST7789H2_RASET 0x2B +#define ST7789H2_VSCRDEF 0x33 /* Vertical Scroll Definition */ +#define ST7789H2_VSCSAD 0x37 /* Vertical Scroll Start Address of RAM */ +#define ST7789H2_TEARING_EFFECT 0x35 +#define ST7789H2_NORMAL_DISPLAY 0x36 +#define ST7789H2_IDLE_MODE_OFF 0x38 +#define ST7789H2_IDLE_MODE_ON 0x39 +#define ST7789H2_COLOR_MODE 0x3A +#define ST7789H2_PORCH_CTRL 0xB2 +#define ST7789H2_GATE_CTRL 0xB7 +#define ST7789H2_VCOM_SET 0xBB +#define ST7789H2_DISPLAY_OFF 0xBD +#define ST7789H2_LCM_CTRL 0xC0 +#define ST7789H2_VDV_VRH_EN 0xC2 +#define ST7789H2_VDV_SET 0xC4 +#define ST7789H2_VCOMH_OFFSET_SET 0xC5 +#define ST7789H2_FR_CTRL 0xC6 +#define ST7789H2_POWER_CTRL 0xD0 +#define ST7789H2_PV_GAMMA_CTRL 0xE0 +#define ST7789H2_NV_GAMMA_CTRL 0xE1 + +/** + * @} + */ + +/** @defgroup ST7789H2_Exported_Functions ST7789H2 Exported Functions + * @{ + */ +void ST7789H2_Init(void); +void ST7789H2_SetOrientation(uint32_t orientation); +uint16_t ST7789H2_ReadID(void); +void ST7789H2_WriteReg(uint8_t Command, uint8_t *Parameters, uint8_t NbParameters); +uint8_t ST7789H2_ReadReg(uint8_t Command); + +void ST7789H2_DisplayOn(void); +void ST7789H2_DisplayOff(void); +void ST7789H2_SetCursor(uint16_t Xpos, uint16_t Ypos); +void ST7789H2_WritePixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGBCode); +uint16_t ST7789H2_ReadPixel(uint16_t Xpos, uint16_t Ypos); + +void ST7789H2_DrawHLine(uint16_t RGBCode, uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void ST7789H2_DrawVLine(uint16_t RGBCode, uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void ST7789H2_DrawBitmap(uint16_t Xpos, uint16_t Ypos, uint8_t *pbmp); +void ST7789H2_DrawRGBImage(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint16_t Ysize, uint8_t *pdata); + +void ST7789H2_SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); + + +uint16_t ST7789H2_GetLcdPixelWidth(void); +uint16_t ST7789H2_GetLcdPixelHeight(void); + +/* LCD driver structure */ +extern LCD_DrvTypeDef ST7789H2_drv; + +/* LCD IO functions */ +extern void LCD_IO_Init(void); +extern void LCD_IO_WriteMultipleData(uint16_t *pData, uint32_t Size); +extern void LCD_IO_WriteReg(uint8_t Reg); +extern void LCD_IO_WriteData(uint16_t RegValue); +extern uint16_t LCD_IO_ReadData(void); +extern void LCD_IO_Delay(uint32_t delay); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ST7789H2_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/stmpe811/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/stmpe811/Release_Notes.html new file mode 100644 index 00000000..ff8706da --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/stmpe811/Release_Notes.html @@ -0,0 +1,392 @@ + + + + + + + + + + + + + + + + + + + + + Release Notes for STMPE811 Component Driver + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+ +

Release +Notes for STMPE811 Component Driver

+ +

Copyright +2014 STMicroelectronics

+

+
+

 

+ + + + + + +
+ + +

Update History

V2.0.1 +/ 05-June-2017

+ +

Main +Changes

+ + + + + + + + + + +
  • Update comments to be used for PDSC generation

V2.0.0 / 15-December-2014

+ + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + +
    +
  • All functions: update IO_Pin parameter to uint32_t instead of uint16_t
  • Add a return valud for stmpe811_IO_Config() function
  • Important Note: This new version V2.0.0 break the compatibility with V1.0.2, and it need to be used with STM32Cube BSP Common V2.0.0

V1.0.2 / 02-December-2014

+ + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • stmpe811.h: change "\" by "/" in the include path to fix compilation issue under Linux
    +
+ +

V1.0.1 / 11-November-2014

+ + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • Fix limitation related to the selection of alternate function for TS physical IO
    +
  • Fix wrong pins definition of the TS
  • Swap implementation of stmpe811_IO_EnableAF() and stmpe811_IO_DisableAF() functions
    +
  • Miscellaneous code cleanup of comments update
    +
+ +

V1.0.0 / 18-February-2014

+ + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  •  First official release STMPE811 IOExpander component driver
  • +

License

+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/stmpe811/stmpe811.c b/src/port_stm32f7/common/bsp_drivers/Components/stmpe811/stmpe811.c new file mode 100644 index 00000000..c4b88f6c --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/stmpe811/stmpe811.c @@ -0,0 +1,975 @@ +/** + ****************************************************************************** + * @file stmpe811.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the STMPE811 + * IO Expander devices. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stmpe811.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @defgroup STMPE811 + * @{ + */ + +/** @defgroup STMPE811_Private_Types_Definitions + * @{ + */ + +/** @defgroup STMPE811_Private_Defines + * @{ + */ +#define STMPE811_MAX_INSTANCE 2 +/** + * @} + */ + +/** @defgroup STMPE811_Private_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STMPE811_Private_Variables + * @{ + */ + +/* Touch screen driver structure initialization */ +TS_DrvTypeDef stmpe811_ts_drv = +{ + stmpe811_Init, + stmpe811_ReadID, + stmpe811_Reset, + stmpe811_TS_Start, + stmpe811_TS_DetectTouch, + stmpe811_TS_GetXY, + stmpe811_TS_EnableIT, + stmpe811_TS_ClearIT, + stmpe811_TS_ITStatus, + stmpe811_TS_DisableIT, +}; + +/* IO driver structure initialization */ +IO_DrvTypeDef stmpe811_io_drv = +{ + stmpe811_Init, + stmpe811_ReadID, + stmpe811_Reset, + stmpe811_IO_Start, + stmpe811_IO_Config, + stmpe811_IO_WritePin, + stmpe811_IO_ReadPin, + stmpe811_IO_EnableIT, + stmpe811_IO_DisableIT, + stmpe811_IO_ITStatus, + stmpe811_IO_ClearIT, +}; + +/* stmpe811 instances by address */ +uint8_t stmpe811[STMPE811_MAX_INSTANCE] = {0}; +/** + * @} + */ + +/** @defgroup STMPE811_Private_Function_Prototypes + * @{ + */ +static uint8_t stmpe811_GetInstance(uint16_t DeviceAddr); +/** + * @} + */ + +/** @defgroup STMPE811_Private_Functions + * @{ + */ + +/** + * @brief Initialize the stmpe811 and configure the needed hardware resources + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void stmpe811_Init(uint16_t DeviceAddr) +{ + uint8_t instance; + uint8_t empty; + + /* Check if device instance already exists */ + instance = stmpe811_GetInstance(DeviceAddr); + + /* To prevent double initialization */ + if(instance == 0xFF) + { + /* Look for empty instance */ + empty = stmpe811_GetInstance(0); + + if(empty < STMPE811_MAX_INSTANCE) + { + /* Register the current device instance */ + stmpe811[empty] = DeviceAddr; + + /* Initialize IO BUS layer */ + IOE_Init(); + + /* Generate stmpe811 Software reset */ + stmpe811_Reset(DeviceAddr); + } + } +} + +/** + * @brief Reset the stmpe811 by Software. + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void stmpe811_Reset(uint16_t DeviceAddr) +{ + /* Power Down the stmpe811 */ + IOE_Write(DeviceAddr, STMPE811_REG_SYS_CTRL1, 2); + + /* Wait for a delay to ensure registers erasing */ + IOE_Delay(10); + + /* Power On the Codec after the power off => all registers are reinitialized */ + IOE_Write(DeviceAddr, STMPE811_REG_SYS_CTRL1, 0); + + /* Wait for a delay to ensure registers erasing */ + IOE_Delay(2); +} + +/** + * @brief Read the stmpe811 IO Expander device ID. + * @param DeviceAddr: Device address on communication Bus. + * @retval The Device ID (two bytes). + */ +uint16_t stmpe811_ReadID(uint16_t DeviceAddr) +{ + /* Initialize IO BUS layer */ + IOE_Init(); + + /* Return the device ID value */ + return ((IOE_Read(DeviceAddr, STMPE811_REG_CHP_ID_LSB) << 8) |\ + (IOE_Read(DeviceAddr, STMPE811_REG_CHP_ID_MSB))); +} + +/** + * @brief Enable the Global interrupt. + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void stmpe811_EnableGlobalIT(uint16_t DeviceAddr) +{ + uint8_t tmp = 0; + + /* Read the Interrupt Control register */ + tmp = IOE_Read(DeviceAddr, STMPE811_REG_INT_CTRL); + + /* Set the global interrupts to be Enabled */ + tmp |= (uint8_t)STMPE811_GIT_EN; + + /* Write Back the Interrupt Control register */ + IOE_Write(DeviceAddr, STMPE811_REG_INT_CTRL, tmp); +} + +/** + * @brief Disable the Global interrupt. + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void stmpe811_DisableGlobalIT(uint16_t DeviceAddr) +{ + uint8_t tmp = 0; + + /* Read the Interrupt Control register */ + tmp = IOE_Read(DeviceAddr, STMPE811_REG_INT_CTRL); + + /* Set the global interrupts to be Disabled */ + tmp &= ~(uint8_t)STMPE811_GIT_EN; + + /* Write Back the Interrupt Control register */ + IOE_Write(DeviceAddr, STMPE811_REG_INT_CTRL, tmp); + +} + +/** + * @brief Enable the interrupt mode for the selected IT source + * @param DeviceAddr: Device address on communication Bus. + * @param Source: The interrupt source to be configured, could be: + * @arg STMPE811_GIT_IO: IO interrupt + * @arg STMPE811_GIT_ADC : ADC interrupt + * @arg STMPE811_GIT_FE : Touch Screen Controller FIFO Error interrupt + * @arg STMPE811_GIT_FF : Touch Screen Controller FIFO Full interrupt + * @arg STMPE811_GIT_FOV : Touch Screen Controller FIFO Overrun interrupt + * @arg STMPE811_GIT_FTH : Touch Screen Controller FIFO Threshold interrupt + * @arg STMPE811_GIT_TOUCH : Touch Screen Controller Touch Detected interrupt + * @retval None + */ +void stmpe811_EnableITSource(uint16_t DeviceAddr, uint8_t Source) +{ + uint8_t tmp = 0; + + /* Get the current value of the INT_EN register */ + tmp = IOE_Read(DeviceAddr, STMPE811_REG_INT_EN); + + /* Set the interrupts to be Enabled */ + tmp |= Source; + + /* Set the register */ + IOE_Write(DeviceAddr, STMPE811_REG_INT_EN, tmp); +} + +/** + * @brief Disable the interrupt mode for the selected IT source + * @param DeviceAddr: Device address on communication Bus. + * @param Source: The interrupt source to be configured, could be: + * @arg STMPE811_GIT_IO: IO interrupt + * @arg STMPE811_GIT_ADC : ADC interrupt + * @arg STMPE811_GIT_FE : Touch Screen Controller FIFO Error interrupt + * @arg STMPE811_GIT_FF : Touch Screen Controller FIFO Full interrupt + * @arg STMPE811_GIT_FOV : Touch Screen Controller FIFO Overrun interrupt + * @arg STMPE811_GIT_FTH : Touch Screen Controller FIFO Threshold interrupt + * @arg STMPE811_GIT_TOUCH : Touch Screen Controller Touch Detected interrupt + * @retval None + */ +void stmpe811_DisableITSource(uint16_t DeviceAddr, uint8_t Source) +{ + uint8_t tmp = 0; + + /* Get the current value of the INT_EN register */ + tmp = IOE_Read(DeviceAddr, STMPE811_REG_INT_EN); + + /* Set the interrupts to be Enabled */ + tmp &= ~Source; + + /* Set the register */ + IOE_Write(DeviceAddr, STMPE811_REG_INT_EN, tmp); +} + +/** + * @brief Set the global interrupt Polarity. + * @param DeviceAddr: Device address on communication Bus. + * @param Polarity: the IT mode polarity, could be one of the following values: + * @arg STMPE811_POLARITY_LOW: Interrupt line is active Low/Falling edge + * @arg STMPE811_POLARITY_HIGH: Interrupt line is active High/Rising edge + * @retval None + */ +void stmpe811_SetITPolarity(uint16_t DeviceAddr, uint8_t Polarity) +{ + uint8_t tmp = 0; + + /* Get the current register value */ + tmp = IOE_Read(DeviceAddr, STMPE811_REG_INT_CTRL); + + /* Mask the polarity bits */ + tmp &= ~(uint8_t)0x04; + + /* Modify the Interrupt Output line configuration */ + tmp |= Polarity; + + /* Set the new register value */ + IOE_Write(DeviceAddr, STMPE811_REG_INT_CTRL, tmp); + +} + +/** + * @brief Set the global interrupt Type. + * @param DeviceAddr: Device address on communication Bus. + * @param Type: Interrupt line activity type, could be one of the following values: + * @arg STMPE811_TYPE_LEVEL: Interrupt line is active in level model + * @arg STMPE811_TYPE_EDGE: Interrupt line is active in edge model + * @retval None + */ +void stmpe811_SetITType(uint16_t DeviceAddr, uint8_t Type) +{ + uint8_t tmp = 0; + + /* Get the current register value */ + tmp = IOE_Read(DeviceAddr, STMPE811_REG_INT_CTRL); + + /* Mask the type bits */ + tmp &= ~(uint8_t)0x02; + + /* Modify the Interrupt Output line configuration */ + tmp |= Type; + + /* Set the new register value */ + IOE_Write(DeviceAddr, STMPE811_REG_INT_CTRL, tmp); + +} + +/** + * @brief Check the selected Global interrupt source pending bit + * @param DeviceAddr: Device address on communication Bus. + * @param Source: the Global interrupt source to be checked, could be: + * @arg STMPE811_GIT_IO: IO interrupt + * @arg STMPE811_GIT_ADC : ADC interrupt + * @arg STMPE811_GIT_FE : Touch Screen Controller FIFO Error interrupt + * @arg STMPE811_GIT_FF : Touch Screen Controller FIFO Full interrupt + * @arg STMPE811_GIT_FOV : Touch Screen Controller FIFO Overrun interrupt + * @arg STMPE811_GIT_FTH : Touch Screen Controller FIFO Threshold interrupt + * @arg STMPE811_GIT_TOUCH : Touch Screen Controller Touch Detected interrupt + * @retval The checked Global interrupt source status. + */ +uint8_t stmpe811_GlobalITStatus(uint16_t DeviceAddr, uint8_t Source) +{ + /* Return the global IT source status */ + return((IOE_Read(DeviceAddr, STMPE811_REG_INT_STA) & Source) == Source); +} + +/** + * @brief Return the Global interrupts status + * @param DeviceAddr: Device address on communication Bus. + * @param Source: the Global interrupt source to be checked, could be: + * @arg STMPE811_GIT_IO: IO interrupt + * @arg STMPE811_GIT_ADC : ADC interrupt + * @arg STMPE811_GIT_FE : Touch Screen Controller FIFO Error interrupt + * @arg STMPE811_GIT_FF : Touch Screen Controller FIFO Full interrupt + * @arg STMPE811_GIT_FOV : Touch Screen Controller FIFO Overrun interrupt + * @arg STMPE811_GIT_FTH : Touch Screen Controller FIFO Threshold interrupt + * @arg STMPE811_GIT_TOUCH : Touch Screen Controller Touch Detected interrupt + * @retval The checked Global interrupt source status. + */ +uint8_t stmpe811_ReadGITStatus(uint16_t DeviceAddr, uint8_t Source) +{ + /* Return the global IT source status */ + return((IOE_Read(DeviceAddr, STMPE811_REG_INT_STA) & Source)); +} + +/** + * @brief Clear the selected Global interrupt pending bit(s) + * @param DeviceAddr: Device address on communication Bus. + * @param Source: the Global interrupt source to be cleared, could be any combination + * of the following values: + * @arg STMPE811_GIT_IO: IO interrupt + * @arg STMPE811_GIT_ADC : ADC interrupt + * @arg STMPE811_GIT_FE : Touch Screen Controller FIFO Error interrupt + * @arg STMPE811_GIT_FF : Touch Screen Controller FIFO Full interrupt + * @arg STMPE811_GIT_FOV : Touch Screen Controller FIFO Overrun interrupt + * @arg STMPE811_GIT_FTH : Touch Screen Controller FIFO Threshold interrupt + * @arg STMPE811_GIT_TOUCH : Touch Screen Controller Touch Detected interrupt + * @retval None + */ +void stmpe811_ClearGlobalIT(uint16_t DeviceAddr, uint8_t Source) +{ + /* Write 1 to the bits that have to be cleared */ + IOE_Write(DeviceAddr, STMPE811_REG_INT_STA, Source); +} + +/** + * @brief Start the IO functionality use and disable the AF for selected IO pin(s). + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO pin(s) to put in AF. This parameter can be one + * of the following values: + * @arg STMPE811_PIN_x: where x can be from 0 to 7. + * @retval None + */ +void stmpe811_IO_Start(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + uint8_t mode; + + /* Get the current register value */ + mode = IOE_Read(DeviceAddr, STMPE811_REG_SYS_CTRL2); + + /* Set the Functionalities to be Disabled */ + mode &= ~(STMPE811_IO_FCT | STMPE811_ADC_FCT); + + /* Write the new register value */ + IOE_Write(DeviceAddr, STMPE811_REG_SYS_CTRL2, mode); + + /* Disable AF for the selected IO pin(s) */ + stmpe811_IO_DisableAF(DeviceAddr, (uint8_t)IO_Pin); +} + +/** + * @brief Configures the IO pin(s) according to IO mode structure value. + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The output pin to be set or reset. This parameter can be one + * of the following values: + * @arg STMPE811_PIN_x: where x can be from 0 to 7. + * @param IO_Mode: The IO pin mode to configure, could be one of the following values: + * @arg IO_MODE_INPUT + * @arg IO_MODE_OUTPUT + * @arg IO_MODE_IT_RISING_EDGE + * @arg IO_MODE_IT_FALLING_EDGE + * @arg IO_MODE_IT_LOW_LEVEL + * @arg IO_MODE_IT_HIGH_LEVEL + * @retval 0 if no error, IO_Mode if error + */ +uint8_t stmpe811_IO_Config(uint16_t DeviceAddr, uint32_t IO_Pin, IO_ModeTypedef IO_Mode) +{ + uint8_t error_code = 0; + + /* Configure IO pin according to selected IO mode */ + switch(IO_Mode) + { + case IO_MODE_INPUT: /* Input mode */ + stmpe811_IO_InitPin(DeviceAddr, IO_Pin, STMPE811_DIRECTION_IN); + break; + + case IO_MODE_OUTPUT: /* Output mode */ + stmpe811_IO_InitPin(DeviceAddr, IO_Pin, STMPE811_DIRECTION_OUT); + break; + + case IO_MODE_IT_RISING_EDGE: /* Interrupt rising edge mode */ + stmpe811_IO_EnableIT(DeviceAddr); + stmpe811_IO_EnablePinIT(DeviceAddr, IO_Pin); + stmpe811_IO_InitPin(DeviceAddr, IO_Pin, STMPE811_DIRECTION_IN); + stmpe811_SetITType(DeviceAddr, STMPE811_TYPE_EDGE); + stmpe811_IO_SetEdgeMode(DeviceAddr, IO_Pin, STMPE811_EDGE_RISING); + break; + + case IO_MODE_IT_FALLING_EDGE: /* Interrupt falling edge mode */ + stmpe811_IO_EnableIT(DeviceAddr); + stmpe811_IO_EnablePinIT(DeviceAddr, IO_Pin); + stmpe811_IO_InitPin(DeviceAddr, IO_Pin, STMPE811_DIRECTION_IN); + stmpe811_SetITType(DeviceAddr, STMPE811_TYPE_EDGE); + stmpe811_IO_SetEdgeMode(DeviceAddr, IO_Pin, STMPE811_EDGE_FALLING); + break; + + case IO_MODE_IT_LOW_LEVEL: /* Low level interrupt mode */ + stmpe811_IO_EnableIT(DeviceAddr); + stmpe811_IO_EnablePinIT(DeviceAddr, IO_Pin); + stmpe811_IO_InitPin(DeviceAddr, IO_Pin, STMPE811_DIRECTION_IN); + stmpe811_SetITType(DeviceAddr, STMPE811_TYPE_LEVEL); + stmpe811_SetITPolarity(DeviceAddr, STMPE811_POLARITY_LOW); + break; + + case IO_MODE_IT_HIGH_LEVEL: /* High level interrupt mode */ + stmpe811_IO_EnableIT(DeviceAddr); + stmpe811_IO_EnablePinIT(DeviceAddr, IO_Pin); + stmpe811_IO_InitPin(DeviceAddr, IO_Pin, STMPE811_DIRECTION_IN); + stmpe811_SetITType(DeviceAddr, STMPE811_TYPE_LEVEL); + stmpe811_SetITPolarity(DeviceAddr, STMPE811_POLARITY_HIGH); + break; + + default: + error_code = (uint8_t) IO_Mode; + break; + } + return error_code; +} + +/** + * @brief Initialize the selected IO pin direction. + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO pin to be configured. This parameter could be any + * combination of the following values: + * @arg STMPE811_PIN_x: Where x can be from 0 to 7. + * @param Direction: could be STMPE811_DIRECTION_IN or STMPE811_DIRECTION_OUT. + * @retval None + */ +void stmpe811_IO_InitPin(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t Direction) +{ + uint8_t tmp = 0; + + /* Get all the Pins direction */ + tmp = IOE_Read(DeviceAddr, STMPE811_REG_IO_DIR); + + /* Set the selected pin direction */ + if (Direction != STMPE811_DIRECTION_IN) + { + tmp |= (uint8_t)IO_Pin; + } + else + { + tmp &= ~(uint8_t)IO_Pin; + } + + /* Write the register new value */ + IOE_Write(DeviceAddr, STMPE811_REG_IO_DIR, tmp); +} + +/** + * @brief Disable the AF for the selected IO pin(s). + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO pin to be configured. This parameter could be any + * combination of the following values: + * @arg STMPE811_PIN_x: Where x can be from 0 to 7. + * @retval None + */ +void stmpe811_IO_DisableAF(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + uint8_t tmp = 0; + + /* Get the current state of the IO_AF register */ + tmp = IOE_Read(DeviceAddr, STMPE811_REG_IO_AF); + + /* Enable the selected pins alternate function */ + tmp |= (uint8_t)IO_Pin; + + /* Write back the new value in IO AF register */ + IOE_Write(DeviceAddr, STMPE811_REG_IO_AF, tmp); + +} + +/** + * @brief Enable the AF for the selected IO pin(s). + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO pin to be configured. This parameter could be any + * combination of the following values: + * @arg STMPE811_PIN_x: Where x can be from 0 to 7. + * @retval None + */ +void stmpe811_IO_EnableAF(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + uint8_t tmp = 0; + + /* Get the current register value */ + tmp = IOE_Read(DeviceAddr, STMPE811_REG_IO_AF); + + /* Enable the selected pins alternate function */ + tmp &= ~(uint8_t)IO_Pin; + + /* Write back the new register value */ + IOE_Write(DeviceAddr, STMPE811_REG_IO_AF, tmp); +} + +/** + * @brief Configure the Edge for which a transition is detectable for the + * selected pin. + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO pin to be configured. This parameter could be any + * combination of the following values: + * @arg STMPE811_PIN_x: Where x can be from 0 to 7. + * @param Edge: The edge which will be detected. This parameter can be one or + * a combination of following values: STMPE811_EDGE_FALLING and STMPE811_EDGE_RISING . + * @retval None + */ +void stmpe811_IO_SetEdgeMode(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t Edge) +{ + uint8_t tmp1 = 0, tmp2 = 0; + + /* Get the current registers values */ + tmp1 = IOE_Read(DeviceAddr, STMPE811_REG_IO_FE); + tmp2 = IOE_Read(DeviceAddr, STMPE811_REG_IO_RE); + + /* Disable the Falling Edge */ + tmp1 &= ~(uint8_t)IO_Pin; + + /* Disable the Falling Edge */ + tmp2 &= ~(uint8_t)IO_Pin; + + /* Enable the Falling edge if selected */ + if (Edge & STMPE811_EDGE_FALLING) + { + tmp1 |= (uint8_t)IO_Pin; + } + + /* Enable the Rising edge if selected */ + if (Edge & STMPE811_EDGE_RISING) + { + tmp2 |= (uint8_t)IO_Pin; + } + + /* Write back the new registers values */ + IOE_Write(DeviceAddr, STMPE811_REG_IO_FE, tmp1); + IOE_Write(DeviceAddr, STMPE811_REG_IO_RE, tmp2); +} + +/** + * @brief Write a new IO pin state. + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The output pin to be set or reset. This parameter can be one + * of the following values: + * @arg STMPE811_PIN_x: where x can be from 0 to 7. + * @param PinState: The new IO pin state. + * @retval None + */ +void stmpe811_IO_WritePin(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t PinState) +{ + /* Apply the bit value to the selected pin */ + if (PinState != 0) + { + /* Set the register */ + IOE_Write(DeviceAddr, STMPE811_REG_IO_SET_PIN, (uint8_t)IO_Pin); + } + else + { + /* Set the register */ + IOE_Write(DeviceAddr, STMPE811_REG_IO_CLR_PIN, (uint8_t)IO_Pin); + } +} + +/** + * @brief Return the state of the selected IO pin(s). + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The output pin to be set or reset. This parameter can be one + * of the following values: + * @arg STMPE811_PIN_x: where x can be from 0 to 7. + * @retval IO pin(s) state. + */ +uint32_t stmpe811_IO_ReadPin(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + return((uint32_t)(IOE_Read(DeviceAddr, STMPE811_REG_IO_MP_STA) & (uint8_t)IO_Pin)); +} + +/** + * @brief Enable the global IO interrupt source. + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void stmpe811_IO_EnableIT(uint16_t DeviceAddr) +{ + IOE_ITConfig(); + + /* Enable global IO IT source */ + stmpe811_EnableITSource(DeviceAddr, STMPE811_GIT_IO); + + /* Enable global interrupt */ + stmpe811_EnableGlobalIT(DeviceAddr); +} + +/** + * @brief Disable the global IO interrupt source. + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void stmpe811_IO_DisableIT(uint16_t DeviceAddr) +{ + /* Disable the global interrupt */ + stmpe811_DisableGlobalIT(DeviceAddr); + + /* Disable global IO IT source */ + stmpe811_DisableITSource(DeviceAddr, STMPE811_GIT_IO); +} + +/** + * @brief Enable interrupt mode for the selected IO pin(s). + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO interrupt to be enabled. This parameter could be any + * combination of the following values: + * @arg STMPE811_PIN_x: where x can be from 0 to 7. + * @retval None + */ +void stmpe811_IO_EnablePinIT(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + uint8_t tmp = 0; + + /* Get the IO interrupt state */ + tmp = IOE_Read(DeviceAddr, STMPE811_REG_IO_INT_EN); + + /* Set the interrupts to be enabled */ + tmp |= (uint8_t)IO_Pin; + + /* Write the register new value */ + IOE_Write(DeviceAddr, STMPE811_REG_IO_INT_EN, tmp); +} + +/** + * @brief Disable interrupt mode for the selected IO pin(s). + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO interrupt to be disabled. This parameter could be any + * combination of the following values: + * @arg STMPE811_PIN_x: where x can be from 0 to 7. + * @retval None + */ +void stmpe811_IO_DisablePinIT(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + uint8_t tmp = 0; + + /* Get the IO interrupt state */ + tmp = IOE_Read(DeviceAddr, STMPE811_REG_IO_INT_EN); + + /* Set the interrupts to be Disabled */ + tmp &= ~(uint8_t)IO_Pin; + + /* Write the register new value */ + IOE_Write(DeviceAddr, STMPE811_REG_IO_INT_EN, tmp); +} + +/** + * @brief Check the status of the selected IO interrupt pending bit + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: The IO interrupt to be checked could be: + * @arg STMPE811_PIN_x Where x can be from 0 to 7. + * @retval Status of the checked IO pin(s). + */ +uint32_t stmpe811_IO_ITStatus(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + /* Get the Interrupt status */ + return(IOE_Read(DeviceAddr, STMPE811_REG_IO_INT_STA) & (uint8_t)IO_Pin); +} + +/** + * @brief Clear the selected IO interrupt pending bit(s). + * @param DeviceAddr: Device address on communication Bus. + * @param IO_Pin: the IO interrupt to be cleared, could be: + * @arg STMPE811_PIN_x: Where x can be from 0 to 7. + * @retval None + */ +void stmpe811_IO_ClearIT(uint16_t DeviceAddr, uint32_t IO_Pin) +{ + /* Clear the global IO IT pending bit */ + stmpe811_ClearGlobalIT(DeviceAddr, STMPE811_GIT_IO); + + /* Clear the IO IT pending bit(s) */ + IOE_Write(DeviceAddr, STMPE811_REG_IO_INT_STA, (uint8_t)IO_Pin); + + /* Clear the Edge detection pending bit*/ + IOE_Write(DeviceAddr, STMPE811_REG_IO_ED, (uint8_t)IO_Pin); + + /* Clear the Rising edge pending bit */ + IOE_Write(DeviceAddr, STMPE811_REG_IO_RE, (uint8_t)IO_Pin); + + /* Clear the Falling edge pending bit */ + IOE_Write(DeviceAddr, STMPE811_REG_IO_FE, (uint8_t)IO_Pin); +} + +/** + * @brief Configures the touch Screen Controller (Single point detection) + * @param DeviceAddr: Device address on communication Bus. + * @retval None. + */ +void stmpe811_TS_Start(uint16_t DeviceAddr) +{ + uint8_t mode; + + /* Get the current register value */ + mode = IOE_Read(DeviceAddr, STMPE811_REG_SYS_CTRL2); + + /* Set the Functionalities to be Enabled */ + mode &= ~(STMPE811_IO_FCT); + + /* Write the new register value */ + IOE_Write(DeviceAddr, STMPE811_REG_SYS_CTRL2, mode); + + /* Select TSC pins in TSC alternate mode */ + stmpe811_IO_EnableAF(DeviceAddr, STMPE811_TOUCH_IO_ALL); + + /* Set the Functionalities to be Enabled */ + mode &= ~(STMPE811_TS_FCT | STMPE811_ADC_FCT); + + /* Set the new register value */ + IOE_Write(DeviceAddr, STMPE811_REG_SYS_CTRL2, mode); + + /* Select Sample Time, bit number and ADC Reference */ + IOE_Write(DeviceAddr, STMPE811_REG_ADC_CTRL1, 0x49); + + /* Wait for 2 ms */ + IOE_Delay(2); + + /* Select the ADC clock speed: 3.25 MHz */ + IOE_Write(DeviceAddr, STMPE811_REG_ADC_CTRL2, 0x01); + + /* Select 2 nF filter capacitor */ + /* Configuration: + - Touch average control : 4 samples + - Touch delay time : 500 uS + - Panel driver setting time: 500 uS + */ + IOE_Write(DeviceAddr, STMPE811_REG_TSC_CFG, 0x9A); + + /* Configure the Touch FIFO threshold: single point reading */ + IOE_Write(DeviceAddr, STMPE811_REG_FIFO_TH, 0x01); + + /* Clear the FIFO memory content. */ + IOE_Write(DeviceAddr, STMPE811_REG_FIFO_STA, 0x01); + + /* Put the FIFO back into operation mode */ + IOE_Write(DeviceAddr, STMPE811_REG_FIFO_STA, 0x00); + + /* Set the range and accuracy pf the pressure measurement (Z) : + - Fractional part :7 + - Whole part :1 + */ + IOE_Write(DeviceAddr, STMPE811_REG_TSC_FRACT_XYZ, 0x01); + + /* Set the driving capability (limit) of the device for TSC pins: 50mA */ + IOE_Write(DeviceAddr, STMPE811_REG_TSC_I_DRIVE, 0x01); + + /* Touch screen control configuration (enable TSC): + - No window tracking index + - XYZ acquisition mode + */ + IOE_Write(DeviceAddr, STMPE811_REG_TSC_CTRL, 0x01); + + /* Clear all the status pending bits if any */ + IOE_Write(DeviceAddr, STMPE811_REG_INT_STA, 0xFF); + + /* Wait for 2 ms delay */ + IOE_Delay(2); +} + +/** + * @brief Return if there is touch detected or not. + * @param DeviceAddr: Device address on communication Bus. + * @retval Touch detected state. + */ +uint8_t stmpe811_TS_DetectTouch(uint16_t DeviceAddr) +{ + uint8_t state; + uint8_t ret = 0; + + state = ((IOE_Read(DeviceAddr, STMPE811_REG_TSC_CTRL) & (uint8_t)STMPE811_TS_CTRL_STATUS) == (uint8_t)0x80); + + if(state > 0) + { + if(IOE_Read(DeviceAddr, STMPE811_REG_FIFO_SIZE) > 0) + { + ret = 1; + } + } + else + { + /* Reset FIFO */ + IOE_Write(DeviceAddr, STMPE811_REG_FIFO_STA, 0x01); + /* Enable the FIFO again */ + IOE_Write(DeviceAddr, STMPE811_REG_FIFO_STA, 0x00); + } + + return ret; +} + +/** + * @brief Get the touch screen X and Y positions values + * @param DeviceAddr: Device address on communication Bus. + * @param X: Pointer to X position value + * @param Y: Pointer to Y position value + * @retval None. + */ +void stmpe811_TS_GetXY(uint16_t DeviceAddr, uint16_t *X, uint16_t *Y) +{ + uint8_t dataXYZ[4]; + uint32_t uldataXYZ; + + IOE_ReadMultiple(DeviceAddr, STMPE811_REG_TSC_DATA_NON_INC, dataXYZ, sizeof(dataXYZ)) ; + + /* Calculate positions values */ + uldataXYZ = (dataXYZ[0] << 24)|(dataXYZ[1] << 16)|(dataXYZ[2] << 8)|(dataXYZ[3] << 0); + *X = (uldataXYZ >> 20) & 0x00000FFF; + *Y = (uldataXYZ >> 8) & 0x00000FFF; + + /* Reset FIFO */ + IOE_Write(DeviceAddr, STMPE811_REG_FIFO_STA, 0x01); + /* Enable the FIFO again */ + IOE_Write(DeviceAddr, STMPE811_REG_FIFO_STA, 0x00); +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void stmpe811_TS_EnableIT(uint16_t DeviceAddr) +{ + IOE_ITConfig(); + + /* Enable global TS IT source */ + stmpe811_EnableITSource(DeviceAddr, STMPE811_TS_IT); + + /* Enable global interrupt */ + stmpe811_EnableGlobalIT(DeviceAddr); +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void stmpe811_TS_DisableIT(uint16_t DeviceAddr) +{ + /* Disable global interrupt */ + stmpe811_DisableGlobalIT(DeviceAddr); + + /* Disable global TS IT source */ + stmpe811_DisableITSource(DeviceAddr, STMPE811_TS_IT); +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval TS interrupts status + */ +uint8_t stmpe811_TS_ITStatus(uint16_t DeviceAddr) +{ + /* Return TS interrupts status */ + return(stmpe811_ReadGITStatus(DeviceAddr, STMPE811_TS_IT)); +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void stmpe811_TS_ClearIT(uint16_t DeviceAddr) +{ + /* Clear the global TS IT source */ + stmpe811_ClearGlobalIT(DeviceAddr, STMPE811_TS_IT); +} + +/** + * @brief Check if the device instance of the selected address is already registered + * and return its index + * @param DeviceAddr: Device address on communication Bus. + * @retval Index of the device instance if registered, 0xFF if not. + */ +static uint8_t stmpe811_GetInstance(uint16_t DeviceAddr) +{ + uint8_t idx = 0; + + /* Check all the registered instances */ + for(idx = 0; idx < STMPE811_MAX_INSTANCE ; idx ++) + { + if(stmpe811[idx] == DeviceAddr) + { + return idx; + } + } + + return 0xFF; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/stmpe811/stmpe811.h b/src/port_stm32f7/common/bsp_drivers/Components/stmpe811/stmpe811.h new file mode 100644 index 00000000..0ef182ec --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/stmpe811/stmpe811.h @@ -0,0 +1,289 @@ +/** + ****************************************************************************** + * @file stmpe811.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for the + * stmpe811.c IO expander driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STMPE811_H +#define __STMPE811_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "../Common/ts.h" +#include "../Common/io.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @defgroup STMPE811 + * @{ + */ + +/** @defgroup STMPE811_Exported_Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STMPE811_Exported_Constants + * @{ + */ + +/* Chip IDs */ +#define STMPE811_ID 0x0811 + +/* Identification registers & System Control */ +#define STMPE811_REG_CHP_ID_LSB 0x00 +#define STMPE811_REG_CHP_ID_MSB 0x01 +#define STMPE811_REG_ID_VER 0x02 + +/* Global interrupt Enable bit */ +#define STMPE811_GIT_EN 0x01 + +/* IO expander functionalities */ +#define STMPE811_ADC_FCT 0x01 +#define STMPE811_TS_FCT 0x02 +#define STMPE811_IO_FCT 0x04 +#define STMPE811_TEMPSENS_FCT 0x08 + +/* Global Interrupts definitions */ +#define STMPE811_GIT_IO 0x80 /* IO interrupt */ +#define STMPE811_GIT_ADC 0x40 /* ADC interrupt */ +#define STMPE811_GIT_TEMP 0x20 /* Not implemented */ +#define STMPE811_GIT_FE 0x10 /* FIFO empty interrupt */ +#define STMPE811_GIT_FF 0x08 /* FIFO full interrupt */ +#define STMPE811_GIT_FOV 0x04 /* FIFO overflowed interrupt */ +#define STMPE811_GIT_FTH 0x02 /* FIFO above threshold interrupt */ +#define STMPE811_GIT_TOUCH 0x01 /* Touch is detected interrupt */ +#define STMPE811_ALL_GIT 0x1F /* All global interrupts */ +#define STMPE811_TS_IT (STMPE811_GIT_TOUCH | STMPE811_GIT_FTH | STMPE811_GIT_FOV | STMPE811_GIT_FF | STMPE811_GIT_FE) /* Touch screen interrupts */ + +/* General Control Registers */ +#define STMPE811_REG_SYS_CTRL1 0x03 +#define STMPE811_REG_SYS_CTRL2 0x04 +#define STMPE811_REG_SPI_CFG 0x08 + +/* Interrupt system Registers */ +#define STMPE811_REG_INT_CTRL 0x09 +#define STMPE811_REG_INT_EN 0x0A +#define STMPE811_REG_INT_STA 0x0B +#define STMPE811_REG_IO_INT_EN 0x0C +#define STMPE811_REG_IO_INT_STA 0x0D + +/* IO Registers */ +#define STMPE811_REG_IO_SET_PIN 0x10 +#define STMPE811_REG_IO_CLR_PIN 0x11 +#define STMPE811_REG_IO_MP_STA 0x12 +#define STMPE811_REG_IO_DIR 0x13 +#define STMPE811_REG_IO_ED 0x14 +#define STMPE811_REG_IO_RE 0x15 +#define STMPE811_REG_IO_FE 0x16 +#define STMPE811_REG_IO_AF 0x17 + +/* ADC Registers */ +#define STMPE811_REG_ADC_INT_EN 0x0E +#define STMPE811_REG_ADC_INT_STA 0x0F +#define STMPE811_REG_ADC_CTRL1 0x20 +#define STMPE811_REG_ADC_CTRL2 0x21 +#define STMPE811_REG_ADC_CAPT 0x22 +#define STMPE811_REG_ADC_DATA_CH0 0x30 +#define STMPE811_REG_ADC_DATA_CH1 0x32 +#define STMPE811_REG_ADC_DATA_CH2 0x34 +#define STMPE811_REG_ADC_DATA_CH3 0x36 +#define STMPE811_REG_ADC_DATA_CH4 0x38 +#define STMPE811_REG_ADC_DATA_CH5 0x3A +#define STMPE811_REG_ADC_DATA_CH6 0x3B +#define STMPE811_REG_ADC_DATA_CH7 0x3C + +/* Touch Screen Registers */ +#define STMPE811_REG_TSC_CTRL 0x40 +#define STMPE811_REG_TSC_CFG 0x41 +#define STMPE811_REG_WDM_TR_X 0x42 +#define STMPE811_REG_WDM_TR_Y 0x44 +#define STMPE811_REG_WDM_BL_X 0x46 +#define STMPE811_REG_WDM_BL_Y 0x48 +#define STMPE811_REG_FIFO_TH 0x4A +#define STMPE811_REG_FIFO_STA 0x4B +#define STMPE811_REG_FIFO_SIZE 0x4C +#define STMPE811_REG_TSC_DATA_X 0x4D +#define STMPE811_REG_TSC_DATA_Y 0x4F +#define STMPE811_REG_TSC_DATA_Z 0x51 +#define STMPE811_REG_TSC_DATA_XYZ 0x52 +#define STMPE811_REG_TSC_FRACT_XYZ 0x56 +#define STMPE811_REG_TSC_DATA_INC 0x57 +#define STMPE811_REG_TSC_DATA_NON_INC 0xD7 +#define STMPE811_REG_TSC_I_DRIVE 0x58 +#define STMPE811_REG_TSC_SHIELD 0x59 + +/* Touch Screen Pins definition */ +#define STMPE811_TOUCH_YD STMPE811_PIN_7 +#define STMPE811_TOUCH_XD STMPE811_PIN_6 +#define STMPE811_TOUCH_YU STMPE811_PIN_5 +#define STMPE811_TOUCH_XU STMPE811_PIN_4 +#define STMPE811_TOUCH_IO_ALL (uint32_t)(STMPE811_TOUCH_YD | STMPE811_TOUCH_XD | STMPE811_TOUCH_YU | STMPE811_TOUCH_XU) + +/* IO Pins definition */ +#define STMPE811_PIN_0 0x01 +#define STMPE811_PIN_1 0x02 +#define STMPE811_PIN_2 0x04 +#define STMPE811_PIN_3 0x08 +#define STMPE811_PIN_4 0x10 +#define STMPE811_PIN_5 0x20 +#define STMPE811_PIN_6 0x40 +#define STMPE811_PIN_7 0x80 +#define STMPE811_PIN_ALL 0xFF + +/* IO Pins directions */ +#define STMPE811_DIRECTION_IN 0x00 +#define STMPE811_DIRECTION_OUT 0x01 + +/* IO IT types */ +#define STMPE811_TYPE_LEVEL 0x00 +#define STMPE811_TYPE_EDGE 0x02 + +/* IO IT polarity */ +#define STMPE811_POLARITY_LOW 0x00 +#define STMPE811_POLARITY_HIGH 0x04 + +/* IO Pin IT edge modes */ +#define STMPE811_EDGE_FALLING 0x01 +#define STMPE811_EDGE_RISING 0x02 + +/* TS registers masks */ +#define STMPE811_TS_CTRL_ENABLE 0x01 +#define STMPE811_TS_CTRL_STATUS 0x80 +/** + * @} + */ + +/** @defgroup STMPE811_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STMPE811_Exported_Functions + * @{ + */ + +/** + * @brief STMPE811 Control functions + */ +void stmpe811_Init(uint16_t DeviceAddr); +void stmpe811_Reset(uint16_t DeviceAddr); +uint16_t stmpe811_ReadID(uint16_t DeviceAddr); +void stmpe811_EnableGlobalIT(uint16_t DeviceAddr); +void stmpe811_DisableGlobalIT(uint16_t DeviceAddr); +void stmpe811_EnableITSource(uint16_t DeviceAddr, uint8_t Source); +void stmpe811_DisableITSource(uint16_t DeviceAddr, uint8_t Source); +void stmpe811_SetITPolarity(uint16_t DeviceAddr, uint8_t Polarity); +void stmpe811_SetITType(uint16_t DeviceAddr, uint8_t Type); +uint8_t stmpe811_GlobalITStatus(uint16_t DeviceAddr, uint8_t Source); +uint8_t stmpe811_ReadGITStatus(uint16_t DeviceAddr, uint8_t Source); +void stmpe811_ClearGlobalIT(uint16_t DeviceAddr, uint8_t Source); + +/** + * @brief STMPE811 IO functionalities functions + */ +void stmpe811_IO_Start(uint16_t DeviceAddr, uint32_t IO_Pin); +uint8_t stmpe811_IO_Config(uint16_t DeviceAddr, uint32_t IO_Pin, IO_ModeTypedef IO_Mode); +void stmpe811_IO_InitPin(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t Direction); +void stmpe811_IO_EnableAF(uint16_t DeviceAddr, uint32_t IO_Pin); +void stmpe811_IO_DisableAF(uint16_t DeviceAddr, uint32_t IO_Pin); +void stmpe811_IO_SetEdgeMode(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t Edge); +void stmpe811_IO_WritePin(uint16_t DeviceAddr, uint32_t IO_Pin, uint8_t PinState); +uint32_t stmpe811_IO_ReadPin(uint16_t DeviceAddr, uint32_t IO_Pin); +void stmpe811_IO_EnableIT(uint16_t DeviceAddr); +void stmpe811_IO_DisableIT(uint16_t DeviceAddr); +void stmpe811_IO_EnablePinIT(uint16_t DeviceAddr, uint32_t IO_Pin); +void stmpe811_IO_DisablePinIT(uint16_t DeviceAddr, uint32_t IO_Pin); +uint32_t stmpe811_IO_ITStatus(uint16_t DeviceAddr, uint32_t IO_Pin); +void stmpe811_IO_ClearIT(uint16_t DeviceAddr, uint32_t IO_Pin); + +/** + * @brief STMPE811 Touch screen functionalities functions + */ +void stmpe811_TS_Start(uint16_t DeviceAddr); +uint8_t stmpe811_TS_DetectTouch(uint16_t DeviceAddr); +void stmpe811_TS_GetXY(uint16_t DeviceAddr, uint16_t *X, uint16_t *Y); +void stmpe811_TS_EnableIT(uint16_t DeviceAddr); +void stmpe811_TS_DisableIT(uint16_t DeviceAddr); +uint8_t stmpe811_TS_ITStatus (uint16_t DeviceAddr); +void stmpe811_TS_ClearIT (uint16_t DeviceAddr); + +void IOE_Init(void); +void IOE_ITConfig (void); +void IOE_Delay(uint32_t delay); +void IOE_Write(uint8_t addr, uint8_t reg, uint8_t value); +uint8_t IOE_Read(uint8_t addr, uint8_t reg); +uint16_t IOE_ReadMultiple(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t length); + +/* Touch screen driver structure */ +extern TS_DrvTypeDef stmpe811_ts_drv; + +/* IO driver structure */ +extern IO_DrvTypeDef stmpe811_io_drv; + +#ifdef __cplusplus +} +#endif +#endif /* __STMPE811_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ts3510/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/ts3510/Release_Notes.html new file mode 100644 index 00000000..b7e1068b --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ts3510/Release_Notes.html @@ -0,0 +1,294 @@ + + + + + + + + + + + + + + + + + + + + + Release Notes for TS3510 Component Driver + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for TS3510 Component Driver

+

Copyright 2014 STMicroelectronics

+

+
+

 

+ + + + + + +
+ + +

Update History

+

V1.0.2 +/ 05-June-2017

+ +

Main +Changes

+ + + + + + + + + + +
  • Update comments to be used for PDSC generation

V1.0.1 / 02-December-2014

+ + + + + + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • ts3510.h: change "\" by "/" in the include path to fix compilation issue under Linux
  • +
+ +

V1.0.0 / 18-February-2014

+ + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + +
    +
  • First official release of TS3510 TS component driver
  • +

License

+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ts3510/ts3510.c b/src/port_stm32f7/common/bsp_drivers/Components/ts3510/ts3510.c new file mode 100644 index 00000000..2c1da8bd --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ts3510/ts3510.c @@ -0,0 +1,254 @@ +/** + ****************************************************************************** + * @file ts3510.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the TS3510 + * IO Expander devices. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "ts3510.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Component + * @{ + */ + +/** @defgroup TS3510 + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ + +/** @defgroup TS3510_Private_Types_Definitions + * @{ + */ + +/* Private define ------------------------------------------------------------*/ + +/** @defgroup TS3510_Private_Defines + * @{ + */ + +/* Private macro -------------------------------------------------------------*/ + +/** @defgroup TS3510_Private_Macros + * @{ + */ + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup TS3510_Private_Variables + * @{ + */ + +/* Touch screen driver structure initialization */ +TS_DrvTypeDef ts3510_ts_drv = +{ + ts3510_Init, + ts3510_ReadID, + ts3510_Reset, + + ts3510_TS_Start, + ts3510_TS_DetectTouch, + ts3510_TS_GetXY, + + ts3510_TS_EnableIT, + ts3510_TS_ClearIT, + ts3510_TS_ITStatus, + ts3510_TS_DisableIT, +}; + +/** + * @} + */ + +/* Private function prototypes -----------------------------------------------*/ + +/** @defgroup ts3510_Private_Function_Prototypes + * @{ + */ + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup ts3510_Private_Functions + * @{ + */ + +/** + * @brief Initialize the ts3510 and configure the needed hardware resources + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void ts3510_Init(uint16_t DeviceAddr) +{ + /* Initialize IO BUS layer */ + IOE_Init(); + +} + +/** + * @brief Reset the ts3510 by Software. + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void ts3510_Reset(uint16_t DeviceAddr) +{ + +} + +/** + * @brief Read the ts3510 IO Expander device ID. + * @param DeviceAddr: Device address on communication Bus. + * @retval The Device ID (two bytes). + */ +uint16_t ts3510_ReadID(uint16_t DeviceAddr) +{ + return 0; +} + +/** + * @brief Configures the touch Screen Controller (Single point detection) + * @param DeviceAddr: Device address on communication Bus. + * @retval None. + */ +void ts3510_TS_Start(uint16_t DeviceAddr) +{ +} + +/** + * @brief Return if there is touch detected or not. + * @param DeviceAddr: Device address on communication Bus. + * @retval Touch detected state. + */ +uint8_t ts3510_TS_DetectTouch(uint16_t DeviceAddr) +{ + uint8_t aBufferTS[11]; + uint8_t aTmpBuffer[2] = {TS3510_READ_CMD, TS3510_WRITE_CMD}; + + /* Prepare for LCD read data */ + IOE_WriteMultiple(DeviceAddr, TS3510_SEND_CMD_REG, aTmpBuffer, 2); + + /* Read TS data from LCD */ + IOE_ReadMultiple(DeviceAddr, TS3510_READ_BLOCK_REG, aBufferTS, 11); + + /* check for first byte */ + if((aBufferTS[1] == 0xFF) && (aBufferTS[2] == 0xFF) && (aBufferTS[3] == 0xFF) && (aBufferTS[4] == 0xFF)) + { + return 0; + } + else + { + return 1; + } +} + +/** + * @brief Get the touch screen X and Y positions values + * @param DeviceAddr: Device address on communication Bus. + * @param X: Pointer to X position value + * @param Y: Pointer to Y position value + * @retval None. + */ +void ts3510_TS_GetXY(uint16_t DeviceAddr, uint16_t *X, uint16_t *Y) +{ + uint8_t aBufferTS[11]; + uint8_t aTmpBuffer[2] = {TS3510_READ_CMD, TS3510_WRITE_CMD}; + + /* Prepare for LCD read data */ + IOE_WriteMultiple(DeviceAddr, TS3510_SEND_CMD_REG, aTmpBuffer, 2); + + /* Read TS data from LCD */ + IOE_ReadMultiple(DeviceAddr, TS3510_READ_BLOCK_REG, aBufferTS, 11); + + /* Calculate positions */ + *X = (((aBufferTS[1] << 8) | aBufferTS[2]) << 12) / 640; + *Y = (((aBufferTS[3] << 8) | aBufferTS[4]) << 12) / 480; + + /* set position to be relative to 12bits resolution */ +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void ts3510_TS_EnableIT(uint16_t DeviceAddr) +{ +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void ts3510_TS_DisableIT(uint16_t DeviceAddr) +{ +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval TS interrupts status + */ +uint8_t ts3510_TS_ITStatus(uint16_t DeviceAddr) +{ + return 0; +} + +/** + * @brief Configure the selected source to generate a global interrupt or not + * @param DeviceAddr: Device address on communication Bus. + * @retval None + */ +void ts3510_TS_ClearIT(uint16_t DeviceAddr) +{ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/ts3510/ts3510.h b/src/port_stm32f7/common/bsp_drivers/Components/ts3510/ts3510.h new file mode 100644 index 00000000..08eb1d63 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/ts3510/ts3510.h @@ -0,0 +1,139 @@ +/** + ****************************************************************************** + * @file ts3510.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for the + * ts3510.c IO expander driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2014 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __TS3510_H +#define __TS3510_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "../Common/ts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Component + * @{ + */ + +/** @defgroup TS3510 + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ + +/** @defgroup TS3510_Exported_Types + * @{ + */ + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup TS3510_Exported_Constants + * @{ + */ + +/* */ +#define TS3510_READ_BLOCK_REG 0x8A +#define TS3510_SEND_CMD_REG 0x00 +#define TS3510_READ_CMD 0x81 +#define TS3510_WRITE_CMD 0x08 + + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ + +/** @defgroup ts3510_Exported_Macros + * @{ + */ + +/* Exported functions --------------------------------------------------------*/ + +/** @defgroup ts3510_Exported_Functions + * @{ + */ + +/** + * @brief ts3510 Control functions + */ +void ts3510_Init(uint16_t DeviceAddr); +void ts3510_Reset(uint16_t DeviceAddr); +uint16_t ts3510_ReadID(uint16_t DeviceAddr); +void ts3510_TS_Start(uint16_t DeviceAddr); +uint8_t ts3510_TS_DetectTouch(uint16_t DeviceAddr); +void ts3510_TS_GetXY(uint16_t DeviceAddr, uint16_t *X, uint16_t *Y); +void ts3510_TS_EnableIT(uint16_t DeviceAddr); +void ts3510_TS_DisableIT(uint16_t DeviceAddr); +uint8_t ts3510_TS_ITStatus (uint16_t DeviceAddr); +void ts3510_TS_ClearIT (uint16_t DeviceAddr); + +void IOE_Init(void); +void IOE_Delay(uint32_t delay); +uint8_t IOE_Read(uint8_t addr, uint8_t reg); +uint16_t IOE_ReadMultiple(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t length); +void IOE_WriteMultiple(uint8_t addr, uint8_t reg, uint8_t *buffer, uint16_t length); + +/* Touch screen driver structure */ +extern TS_DrvTypeDef ts3510_ts_drv; + +#ifdef __cplusplus +} +#endif +#endif /* __TS3510_H */ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/wm8994/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/Components/wm8994/Release_Notes.html new file mode 100644 index 00000000..d9137a5e --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/wm8994/Release_Notes.html @@ -0,0 +1,304 @@ + + + + + + + + + + + + + + + + + + + + + Release Notes for WM8994 Component Driver + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for WM8994 Component Driver

+

Copyright 2016 STMicroelectronics

+

+
+

 

+ + + + + + +
+ + +

Update History

V2.2.1 +/ 24-January-2018

+ +

Main +Changes

+ + + + + + + + + + +
  • Fix output device headphone initialization issue

V2.2.0 +/ 05-June-2017

+ +

Main +Changes

+ + + + + + + + + + +
  • Add support of ColdStartup sequence for headphone
  • Unmute is performed in a gradual way to minimize pop noise.
  • Update wm8994_SetFrequency to support AUDIO_FREQUENCY_32K
  • Update comments to be used for PDSC generation

V2.1.0 / 22-February-2016

+ + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + +
    +
  • wm8994.c
  • +
      +
    • Update wm8994_Init() by adding the support of analog microphone connected to INPUT LINE 1, INPUT_DEVICE_DIGITAL_MICROPHONE_1 and INPUT_DEVICE_DIGITAL_MIC1_MIC2
    • +
    • Add AUDIO_FREQUENCY_32K as possible AudioFreq value
    • +
    +
  • wm8994.h
  • +
      +
    • Add INPUT_DEVICE_DIGITAL_MIC1_MIC2 define
    • +
    +
+ + + + + + +

V2.0.0 / 24-June-2015

+ + + + + + + +

Main +Changes

+ + + + + + + + + + +
  • wm8994.h 
    • Add codec de-initialization function: wm8994_DeInit()
    • Add Audio IO de-initialization function prototype: AUDIO_IO_DeInit()
    • Add INPUT_DEVICE_INPUT_LINE_1 and INPUT_DEVICE_INPUT_LINE_1 support for AUDIO IN
    • Add Input audio volume control support
  • wm8994.c 
    • Update wm8994_Init() function to support the Audio IN
    • Update wm8994_Stop() function to only stop the codec if it was configured
    • Enable VMID_BUF_ENA bit in R57 ANTIPOP register (address 0x39) for all configurations
  • NOTE: This release must be used with BSP Common +driver V4.0.0 or later

V1.0.2 / 12-February-2015

+ + + + + + + +

Main +Changes

+ + + + + + + + + + +
  • wm8994.c: Update the wm8994_Init() function to set the volume after enabling the dynamic charge pump power control mode 

V1.0.1 / 28-November-2014

+ + + + + + + +

Main +Changes

+ + + + + + + + + + +
  • wm8994.h: change "\" by "/" in the include path to fix compilation issue with Linux

V1.0.0 / 18-February-2014

+ + + + + + + +

Main +Changes

+ + + + + + + + + + +
  • First official release of WM8994 AUDIO component driver
  • +

License

+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/Components/wm8994/wm8994.c b/src/port_stm32f7/common/bsp_drivers/Components/wm8994/wm8994.c new file mode 100644 index 00000000..44226fa4 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/wm8994/wm8994.c @@ -0,0 +1,1075 @@ +/** + ****************************************************************************** + * @file wm8994.c + * @author MCD Application Team + * @brief This file provides the WM8994 Audio Codec driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "wm8994.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Components + * @{ + */ + +/** @addtogroup wm8994 + * @brief This file provides a set of functions needed to drive the + * WM8994 audio codec. + * @{ + */ + +/** @defgroup WM8994_Private_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup WM8994_Private_Defines + * @{ + */ +/* Uncomment this line to enable verifying data sent to codec after each write + operation (for debug purpose) */ +#if !defined (VERIFY_WRITTENDATA) +/*#define VERIFY_WRITTENDATA*/ +#endif /* VERIFY_WRITTENDATA */ +/** + * @} + */ + +/** @defgroup WM8994_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup WM8994_Private_Variables + * @{ + */ + +/* Audio codec driver structure initialization */ +AUDIO_DrvTypeDef wm8994_drv = +{ + wm8994_Init, + wm8994_DeInit, + wm8994_ReadID, + + wm8994_Play, + wm8994_Pause, + wm8994_Resume, + wm8994_Stop, + + wm8994_SetFrequency, + wm8994_SetVolume, + wm8994_SetMute, + wm8994_SetOutputMode, + + wm8994_Reset +}; + +static uint32_t outputEnabled = 0; +static uint32_t inputEnabled = 0; +static uint8_t ColdStartup = 1; + +/** + * @} + */ + +/** @defgroup WM8994_Function_Prototypes + * @{ + */ +static uint8_t CODEC_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value); +/** + * @} + */ + + +/** @defgroup WM8994_Private_Functions + * @{ + */ + +/** + * @brief Initializes the audio codec and the control interface. + * @param DeviceAddr: Device address on communication Bus. + * @param OutputInputDevice: can be OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * OUTPUT_DEVICE_BOTH, OUTPUT_DEVICE_AUTO, INPUT_DEVICE_DIGITAL_MICROPHONE_1, + * INPUT_DEVICE_DIGITAL_MICROPHONE_2, INPUT_DEVICE_DIGITAL_MIC1_MIC2, + * INPUT_DEVICE_INPUT_LINE_1 or INPUT_DEVICE_INPUT_LINE_2. + * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) + * @param AudioFreq: Audio Frequency + * @retval 0 if correct communication, else wrong communication + */ +uint32_t wm8994_Init(uint16_t DeviceAddr, uint16_t OutputInputDevice, uint8_t Volume, uint32_t AudioFreq) +{ + uint32_t counter = 0; + uint16_t output_device = OutputInputDevice & 0xFF; + uint16_t input_device = OutputInputDevice & 0xFF00; + uint16_t power_mgnt_reg_1 = 0; + + /* Initialize the Control interface of the Audio Codec */ + AUDIO_IO_Init(); + /* wm8994 Errata Work-Arounds */ + counter += CODEC_IO_Write(DeviceAddr, 0x102, 0x0003); + counter += CODEC_IO_Write(DeviceAddr, 0x817, 0x0000); + counter += CODEC_IO_Write(DeviceAddr, 0x102, 0x0000); + + /* Enable VMID soft start (fast), Start-up Bias Current Enabled */ + counter += CODEC_IO_Write(DeviceAddr, 0x39, 0x006C); + + /* Enable bias generator, Enable VMID */ + if (input_device > 0) + { + counter += CODEC_IO_Write(DeviceAddr, 0x01, 0x0013); + } + else + { + counter += CODEC_IO_Write(DeviceAddr, 0x01, 0x0003); + } + + /* Add Delay */ + AUDIO_IO_Delay(50); + + /* Path Configurations for output */ + if (output_device > 0) + { + outputEnabled = 1; + + switch (output_device) + { + case OUTPUT_DEVICE_SPEAKER: + /* Enable DAC1 (Left), Enable DAC1 (Right), + Disable DAC2 (Left), Disable DAC2 (Right)*/ + counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0C0C); + + /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0000); + + /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0000); + + /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0002); + + /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0002); + break; + + case OUTPUT_DEVICE_HEADPHONE: + /* Disable DAC1 (Left), Disable DAC1 (Right), + Enable DAC2 (Left), Enable DAC2 (Right)*/ + counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303); + + /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001); + + /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001); + + /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0000); + + /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0000); + break; + + case OUTPUT_DEVICE_BOTH: + if (input_device == INPUT_DEVICE_DIGITAL_MIC1_MIC2) + { + /* Enable DAC1 (Left), Enable DAC1 (Right), + also Enable DAC2 (Left), Enable DAC2 (Right)*/ + counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303 | 0x0C0C); + + /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path + Enable the AIF1 Timeslot 1 (Left) to DAC 1 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0003); + + /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path + Enable the AIF1 Timeslot 1 (Right) to DAC 1 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0003); + + /* Enable the AIF1 Timeslot 0 (Left) to DAC 2 (Left) mixer path + Enable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0003); + + /* Enable the AIF1 Timeslot 0 (Right) to DAC 2 (Right) mixer path + Enable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0003); + } + else + { + /* Enable DAC1 (Left), Enable DAC1 (Right), + also Enable DAC2 (Left), Enable DAC2 (Right)*/ + counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303 | 0x0C0C); + + /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001); + + /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001); + + /* Enable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0002); + + /* Enable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0002); + } + break; + + case OUTPUT_DEVICE_AUTO : + default: + /* Disable DAC1 (Left), Disable DAC1 (Right), + Enable DAC2 (Left), Enable DAC2 (Right)*/ + counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303); + + /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001); + + /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001); + + /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0000); + + /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0000); + break; + } + } + else + { + outputEnabled = 0; + } + + /* Path Configurations for input */ + if (input_device > 0) + { + inputEnabled = 1; + switch (input_device) + { + case INPUT_DEVICE_DIGITAL_MICROPHONE_2 : + /* Enable AIF1ADC2 (Left), Enable AIF1ADC2 (Right) + * Enable DMICDAT2 (Left), Enable DMICDAT2 (Right) + * Enable Left ADC, Enable Right ADC */ + counter += CODEC_IO_Write(DeviceAddr, 0x04, 0x0C30); + + /* Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC2 Left/Right Timeslot 1 */ + counter += CODEC_IO_Write(DeviceAddr, 0x450, 0x00DB); + + /* Disable IN1L, IN1R, IN2L, IN2R, Enable Thermal sensor & shutdown */ + counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x6000); + + /* Enable the DMIC2(Left) to AIF1 Timeslot 1 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x608, 0x0002); + + /* Enable the DMIC2(Right) to AIF1 Timeslot 1 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x609, 0x0002); + + /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC2 signal detect */ + counter += CODEC_IO_Write(DeviceAddr, 0x700, 0x000E); + break; + + case INPUT_DEVICE_INPUT_LINE_1 : + /* IN1LN_TO_IN1L, IN1LP_TO_VMID, IN1RN_TO_IN1R, IN1RP_TO_VMID */ + counter += CODEC_IO_Write(DeviceAddr, 0x28, 0x0011); + + /* Disable mute on IN1L_TO_MIXINL and +30dB on IN1L PGA output */ + counter += CODEC_IO_Write(DeviceAddr, 0x29, 0x0035); + + /* Disable mute on IN1R_TO_MIXINL, Gain = +30dB */ + counter += CODEC_IO_Write(DeviceAddr, 0x2A, 0x0035); + + /* Enable AIF1ADC1 (Left), Enable AIF1ADC1 (Right) + * Enable Left ADC, Enable Right ADC */ + counter += CODEC_IO_Write(DeviceAddr, 0x04, 0x0303); + + /* Enable AIF1 DRC1 Signal Detect & DRC in AIF1ADC1 Left/Right Timeslot 0 */ + counter += CODEC_IO_Write(DeviceAddr, 0x440, 0x00DB); + + /* Enable IN1L and IN1R, Disable IN2L and IN2R, Enable Thermal sensor & shutdown */ + counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x6350); + + /* Enable the ADCL(Left) to AIF1 Timeslot 0 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x606, 0x0002); + + /* Enable the ADCR(Right) to AIF1 Timeslot 0 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x607, 0x0002); + + /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC1 signal detect */ + counter += CODEC_IO_Write(DeviceAddr, 0x700, 0x000D); + break; + + case INPUT_DEVICE_DIGITAL_MICROPHONE_1 : + /* Enable AIF1ADC1 (Left), Enable AIF1ADC1 (Right) + * Enable DMICDAT1 (Left), Enable DMICDAT1 (Right) + * Enable Left ADC, Enable Right ADC */ + counter += CODEC_IO_Write(DeviceAddr, 0x04, 0x030C); + + /* Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC1 Left/Right Timeslot 0 */ + counter += CODEC_IO_Write(DeviceAddr, 0x440, 0x00DB); + + /* Disable IN1L, IN1R, IN2L, IN2R, Enable Thermal sensor & shutdown */ + counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x6350); + + /* Enable the DMIC2(Left) to AIF1 Timeslot 0 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x606, 0x0002); + + /* Enable the DMIC2(Right) to AIF1 Timeslot 0 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x607, 0x0002); + + /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC1 signal detect */ + counter += CODEC_IO_Write(DeviceAddr, 0x700, 0x000D); + break; + case INPUT_DEVICE_DIGITAL_MIC1_MIC2 : + /* Enable AIF1ADC1 (Left), Enable AIF1ADC1 (Right) + * Enable DMICDAT1 (Left), Enable DMICDAT1 (Right) + * Enable Left ADC, Enable Right ADC */ + counter += CODEC_IO_Write(DeviceAddr, 0x04, 0x0F3C); + + /* Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC2 Left/Right Timeslot 1 */ + counter += CODEC_IO_Write(DeviceAddr, 0x450, 0x00DB); + + /* Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC1 Left/Right Timeslot 0 */ + counter += CODEC_IO_Write(DeviceAddr, 0x440, 0x00DB); + + /* Disable IN1L, IN1R, Enable IN2L, IN2R, Thermal sensor & shutdown */ + counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x63A0); + + /* Enable the DMIC2(Left) to AIF1 Timeslot 0 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x606, 0x0002); + + /* Enable the DMIC2(Right) to AIF1 Timeslot 0 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x607, 0x0002); + + /* Enable the DMIC2(Left) to AIF1 Timeslot 1 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x608, 0x0002); + + /* Enable the DMIC2(Right) to AIF1 Timeslot 1 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x609, 0x0002); + + /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC1 signal detect */ + counter += CODEC_IO_Write(DeviceAddr, 0x700, 0x000D); + break; + case INPUT_DEVICE_INPUT_LINE_2 : + default: + /* Actually, no other input devices supported */ + counter++; + break; + } + } + else + { + inputEnabled = 0; + } + + /* Clock Configurations */ + switch (AudioFreq) + { + case AUDIO_FREQUENCY_8K: + /* AIF1 Sample Rate = 8 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0003); + break; + + case AUDIO_FREQUENCY_16K: + /* AIF1 Sample Rate = 16 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0033); + break; + + case AUDIO_FREQUENCY_32K: + /* AIF1 Sample Rate = 32 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0063); + break; + + case AUDIO_FREQUENCY_48K: + /* AIF1 Sample Rate = 48 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0083); + break; + + case AUDIO_FREQUENCY_96K: + /* AIF1 Sample Rate = 96 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x00A3); + break; + + case AUDIO_FREQUENCY_11K: + /* AIF1 Sample Rate = 11.025 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0013); + break; + + case AUDIO_FREQUENCY_22K: + /* AIF1 Sample Rate = 22.050 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0043); + break; + + case AUDIO_FREQUENCY_44K: + /* AIF1 Sample Rate = 44.1 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0073); + break; + + default: + /* AIF1 Sample Rate = 48 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0083); + break; + } + + if(input_device == INPUT_DEVICE_DIGITAL_MIC1_MIC2) + { + /* AIF1 Word Length = 16-bits, AIF1 Format = DSP mode */ + counter += CODEC_IO_Write(DeviceAddr, 0x300, 0x4018); + } + else + { + /* AIF1 Word Length = 16-bits, AIF1 Format = I2S (Default Register Value) */ + counter += CODEC_IO_Write(DeviceAddr, 0x300, 0x4010); + } + + /* slave mode */ + counter += CODEC_IO_Write(DeviceAddr, 0x302, 0x0000); + + /* Enable the DSP processing clock for AIF1, Enable the core clock */ + counter += CODEC_IO_Write(DeviceAddr, 0x208, 0x000A); + + /* Enable AIF1 Clock, AIF1 Clock Source = MCLK1 pin */ + counter += CODEC_IO_Write(DeviceAddr, 0x200, 0x0001); + + if (output_device > 0) /* Audio output selected */ + { + if (output_device == OUTPUT_DEVICE_HEADPHONE) + { + /* Select DAC1 (Left) to Left Headphone Output PGA (HPOUT1LVOL) path */ + counter += CODEC_IO_Write(DeviceAddr, 0x2D, 0x0100); + + /* Select DAC1 (Right) to Right Headphone Output PGA (HPOUT1RVOL) path */ + counter += CODEC_IO_Write(DeviceAddr, 0x2E, 0x0100); + + /* Startup sequence for Headphone */ + if(ColdStartup) + { + counter += CODEC_IO_Write(DeviceAddr,0x110,0x8100); + + ColdStartup=0; + /* Add Delay */ + AUDIO_IO_Delay(300); + } + else /* Headphone Warm Start-Up */ + { + counter += CODEC_IO_Write(DeviceAddr,0x110,0x8108); + /* Add Delay */ + AUDIO_IO_Delay(50); + } + + /* Soft un-Mute the AIF1 Timeslot 0 DAC1 path L&R */ + counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0000); + } + /* Analog Output Configuration */ + + /* Enable SPKRVOL PGA, Enable SPKMIXR, Enable SPKLVOL PGA, Enable SPKMIXL */ + counter += CODEC_IO_Write(DeviceAddr, 0x03, 0x0300); + + /* Left Speaker Mixer Volume = 0dB */ + counter += CODEC_IO_Write(DeviceAddr, 0x22, 0x0000); + + /* Speaker output mode = Class D, Right Speaker Mixer Volume = 0dB ((0x23, 0x0100) = class AB)*/ + counter += CODEC_IO_Write(DeviceAddr, 0x23, 0x0000); + + /* Unmute DAC2 (Left) to Left Speaker Mixer (SPKMIXL) path, + Unmute DAC2 (Right) to Right Speaker Mixer (SPKMIXR) path */ + counter += CODEC_IO_Write(DeviceAddr, 0x36, 0x0300); + + /* Enable bias generator, Enable VMID, Enable SPKOUTL, Enable SPKOUTR */ + counter += CODEC_IO_Write(DeviceAddr, 0x01, 0x3003); + + /* Headphone/Speaker Enable */ + + if (input_device == INPUT_DEVICE_DIGITAL_MIC1_MIC2) + { + /* Enable Class W, Class W Envelope Tracking = AIF1 Timeslots 0 and 1 */ + counter += CODEC_IO_Write(DeviceAddr, 0x51, 0x0205); + } + else + { + /* Enable Class W, Class W Envelope Tracking = AIF1 Timeslot 0 */ + counter += CODEC_IO_Write(DeviceAddr, 0x51, 0x0005); + } + + /* Enable bias generator, Enable VMID, Enable HPOUT1 (Left) and Enable HPOUT1 (Right) input stages */ + /* idem for Speaker */ + power_mgnt_reg_1 |= 0x0303 | 0x3003; + counter += CODEC_IO_Write(DeviceAddr, 0x01, power_mgnt_reg_1); + + /* Enable HPOUT1 (Left) and HPOUT1 (Right) intermediate stages */ + counter += CODEC_IO_Write(DeviceAddr, 0x60, 0x0022); + + /* Enable Charge Pump */ + counter += CODEC_IO_Write(DeviceAddr, 0x4C, 0x9F25); + + /* Add Delay */ + AUDIO_IO_Delay(15); + + /* Select DAC1 (Left) to Left Headphone Output PGA (HPOUT1LVOL) path */ + counter += CODEC_IO_Write(DeviceAddr, 0x2D, 0x0001); + + /* Select DAC1 (Right) to Right Headphone Output PGA (HPOUT1RVOL) path */ + counter += CODEC_IO_Write(DeviceAddr, 0x2E, 0x0001); + + /* Enable Left Output Mixer (MIXOUTL), Enable Right Output Mixer (MIXOUTR) */ + /* idem for SPKOUTL and SPKOUTR */ + counter += CODEC_IO_Write(DeviceAddr, 0x03, 0x0030 | 0x0300); + + /* Enable DC Servo and trigger start-up mode on left and right channels */ + counter += CODEC_IO_Write(DeviceAddr, 0x54, 0x0033); + + /* Add Delay */ + AUDIO_IO_Delay(257); + + /* Enable HPOUT1 (Left) and HPOUT1 (Right) intermediate and output stages. Remove clamps */ + counter += CODEC_IO_Write(DeviceAddr, 0x60, 0x00EE); + + /* Unmutes */ + + /* Unmute DAC 1 (Left) */ + counter += CODEC_IO_Write(DeviceAddr, 0x610, 0x00C0); + + /* Unmute DAC 1 (Right) */ + counter += CODEC_IO_Write(DeviceAddr, 0x611, 0x00C0); + + /* Unmute the AIF1 Timeslot 0 DAC path */ + counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0010); + + /* Unmute DAC 2 (Left) */ + counter += CODEC_IO_Write(DeviceAddr, 0x612, 0x00C0); + + /* Unmute DAC 2 (Right) */ + counter += CODEC_IO_Write(DeviceAddr, 0x613, 0x00C0); + + /* Unmute the AIF1 Timeslot 1 DAC2 path */ + counter += CODEC_IO_Write(DeviceAddr, 0x422, 0x0010); + + /* Volume Control */ + wm8994_SetVolume(DeviceAddr, Volume); + } + + if (input_device > 0) /* Audio input selected */ + { + if ((input_device == INPUT_DEVICE_DIGITAL_MICROPHONE_1) || (input_device == INPUT_DEVICE_DIGITAL_MICROPHONE_2)) + { + /* Enable Microphone bias 1 generator, Enable VMID */ + power_mgnt_reg_1 |= 0x0013; + counter += CODEC_IO_Write(DeviceAddr, 0x01, power_mgnt_reg_1); + + /* ADC oversample enable */ + counter += CODEC_IO_Write(DeviceAddr, 0x620, 0x0002); + + /* AIF ADC2 HPF enable, HPF cut = voice mode 1 fc=127Hz at fs=8kHz */ + counter += CODEC_IO_Write(DeviceAddr, 0x411, 0x3800); + } + else if(input_device == INPUT_DEVICE_DIGITAL_MIC1_MIC2) + { + /* Enable Microphone bias 1 generator, Enable VMID */ + power_mgnt_reg_1 |= 0x0013; + counter += CODEC_IO_Write(DeviceAddr, 0x01, power_mgnt_reg_1); + + /* ADC oversample enable */ + counter += CODEC_IO_Write(DeviceAddr, 0x620, 0x0002); + + /* AIF ADC1 HPF enable, HPF cut = voice mode 1 fc=127Hz at fs=8kHz */ + counter += CODEC_IO_Write(DeviceAddr, 0x410, 0x1800); + + /* AIF ADC2 HPF enable, HPF cut = voice mode 1 fc=127Hz at fs=8kHz */ + counter += CODEC_IO_Write(DeviceAddr, 0x411, 0x1800); + } + else if ((input_device == INPUT_DEVICE_INPUT_LINE_1) || (input_device == INPUT_DEVICE_INPUT_LINE_2)) + { + + /* Disable mute on IN1L, IN1L Volume = +0dB */ + counter += CODEC_IO_Write(DeviceAddr, 0x18, 0x000B); + + /* Disable mute on IN1R, IN1R Volume = +0dB */ + counter += CODEC_IO_Write(DeviceAddr, 0x1A, 0x000B); + + /* AIF ADC1 HPF enable, HPF cut = hifi mode fc=4Hz at fs=48kHz */ + counter += CODEC_IO_Write(DeviceAddr, 0x410, 0x1800); + } + /* Volume Control */ + wm8994_SetVolume(DeviceAddr, Volume); + } + /* Return communication control value */ + return counter; +} + +/** + * @brief Deinitializes the audio codec. + * @param None + * @retval None + */ +void wm8994_DeInit(void) +{ + /* Deinitialize Audio Codec interface */ + AUDIO_IO_DeInit(); +} + +/** + * @brief Get the WM8994 ID. + * @param DeviceAddr: Device address on communication Bus. + * @retval The WM8994 ID + */ +uint32_t wm8994_ReadID(uint16_t DeviceAddr) +{ + /* Initialize the Control interface of the Audio Codec */ + AUDIO_IO_Init(); + + return ((uint32_t)AUDIO_IO_Read(DeviceAddr, WM8994_CHIPID_ADDR)); +} + +/** + * @brief Start the audio Codec play feature. + * @note For this codec no Play options are required. + * @param DeviceAddr: Device address on communication Bus. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t wm8994_Play(uint16_t DeviceAddr, uint16_t* pBuffer, uint16_t Size) +{ + uint32_t counter = 0; + + /* Resumes the audio file playing */ + /* Unmute the output first */ + counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_OFF); + + return counter; +} + +/** + * @brief Pauses playing on the audio codec. + * @param DeviceAddr: Device address on communication Bus. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t wm8994_Pause(uint16_t DeviceAddr) +{ + uint32_t counter = 0; + + /* Pause the audio file playing */ + /* Mute the output first */ + counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_ON); + + /* Put the Codec in Power save mode */ + counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x01); + + return counter; +} + +/** + * @brief Resumes playing on the audio codec. + * @param DeviceAddr: Device address on communication Bus. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t wm8994_Resume(uint16_t DeviceAddr) +{ + uint32_t counter = 0; + + /* Resumes the audio file playing */ + /* Unmute the output first */ + counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_OFF); + + return counter; +} + +/** + * @brief Stops audio Codec playing. It powers down the codec. + * @param DeviceAddr: Device address on communication Bus. + * @param CodecPdwnMode: selects the power down mode. + * - CODEC_PDWN_SW: only mutes the audio codec. When resuming from this + * mode the codec keeps the previous initialization + * (no need to re-Initialize the codec registers). + * - CODEC_PDWN_HW: Physically power down the codec. When resuming from this + * mode, the codec is set to default configuration + * (user should re-Initialize the codec in order to + * play again the audio stream). + * @retval 0 if correct communication, else wrong communication + */ +uint32_t wm8994_Stop(uint16_t DeviceAddr, uint32_t CodecPdwnMode) +{ + uint32_t counter = 0; + + if (outputEnabled != 0) + { + /* Mute the output first */ + counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_ON); + + if (CodecPdwnMode == CODEC_PDWN_SW) + { + /* Only output mute required*/ + } + else /* CODEC_PDWN_HW */ + { + /* Mute the AIF1 Timeslot 0 DAC1 path */ + counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0200); + + /* Mute the AIF1 Timeslot 1 DAC2 path */ + counter += CODEC_IO_Write(DeviceAddr, 0x422, 0x0200); + + /* Disable DAC1L_TO_HPOUT1L */ + counter += CODEC_IO_Write(DeviceAddr, 0x2D, 0x0000); + + /* Disable DAC1R_TO_HPOUT1R */ + counter += CODEC_IO_Write(DeviceAddr, 0x2E, 0x0000); + + /* Disable DAC1 and DAC2 */ + counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0000); + + /* Reset Codec by writing in 0x0000 address register */ + counter += CODEC_IO_Write(DeviceAddr, 0x0000, 0x0000); + + outputEnabled = 0; + } + } + return counter; +} + +/** + * @brief Sets higher or lower the codec volume level. + * @param DeviceAddr: Device address on communication Bus. + * @param Volume: a byte value from 0 to 255 (refer to codec registers + * description for more details). + * @retval 0 if correct communication, else wrong communication + */ +uint32_t wm8994_SetVolume(uint16_t DeviceAddr, uint8_t Volume) +{ + uint32_t counter = 0; + uint8_t convertedvol = VOLUME_CONVERT(Volume); + + /* Output volume */ + if (outputEnabled != 0) + { + if(convertedvol > 0x3E) + { + /* Unmute audio codec */ + counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_OFF); + + /* Left Headphone Volume */ + counter += CODEC_IO_Write(DeviceAddr, 0x1C, 0x3F | 0x140); + + /* Right Headphone Volume */ + counter += CODEC_IO_Write(DeviceAddr, 0x1D, 0x3F | 0x140); + + /* Left Speaker Volume */ + counter += CODEC_IO_Write(DeviceAddr, 0x26, 0x3F | 0x140); + + /* Right Speaker Volume */ + counter += CODEC_IO_Write(DeviceAddr, 0x27, 0x3F | 0x140); + } + else if (Volume == 0) + { + /* Mute audio codec */ + counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_ON); + } + else + { + /* Unmute audio codec */ + counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_OFF); + + /* Left Headphone Volume */ + counter += CODEC_IO_Write(DeviceAddr, 0x1C, convertedvol | 0x140); + + /* Right Headphone Volume */ + counter += CODEC_IO_Write(DeviceAddr, 0x1D, convertedvol | 0x140); + + /* Left Speaker Volume */ + counter += CODEC_IO_Write(DeviceAddr, 0x26, convertedvol | 0x140); + + /* Right Speaker Volume */ + counter += CODEC_IO_Write(DeviceAddr, 0x27, convertedvol | 0x140); + } + } + + /* Input volume */ + if (inputEnabled != 0) + { + convertedvol = VOLUME_IN_CONVERT(Volume); + + /* Left AIF1 ADC1 volume */ + counter += CODEC_IO_Write(DeviceAddr, 0x400, convertedvol | 0x100); + + /* Right AIF1 ADC1 volume */ + counter += CODEC_IO_Write(DeviceAddr, 0x401, convertedvol | 0x100); + + /* Left AIF1 ADC2 volume */ + counter += CODEC_IO_Write(DeviceAddr, 0x404, convertedvol | 0x100); + + /* Right AIF1 ADC2 volume */ + counter += CODEC_IO_Write(DeviceAddr, 0x405, convertedvol | 0x100); + } + return counter; +} + +/** + * @brief Enables or disables the mute feature on the audio codec. + * @param DeviceAddr: Device address on communication Bus. + * @param Cmd: AUDIO_MUTE_ON to enable the mute or AUDIO_MUTE_OFF to disable the + * mute mode. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t wm8994_SetMute(uint16_t DeviceAddr, uint32_t Cmd) +{ + uint32_t counter = 0; + + if (outputEnabled != 0) + { + /* Set the Mute mode */ + if(Cmd == AUDIO_MUTE_ON) + { + /* Soft Mute the AIF1 Timeslot 0 DAC1 path L&R */ + counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0200); + + /* Soft Mute the AIF1 Timeslot 1 DAC2 path L&R */ + counter += CODEC_IO_Write(DeviceAddr, 0x422, 0x0200); + } + else /* AUDIO_MUTE_OFF Disable the Mute */ + { + /* Unmute the AIF1 Timeslot 0 DAC1 path L&R */ + counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0010); + + /* Unmute the AIF1 Timeslot 1 DAC2 path L&R */ + counter += CODEC_IO_Write(DeviceAddr, 0x422, 0x0010); + } + } + return counter; +} + +/** + * @brief Switch dynamically (while audio file is played) the output target + * (speaker or headphone). + * @param DeviceAddr: Device address on communication Bus. + * @param Output: specifies the audio output target: OUTPUT_DEVICE_SPEAKER, + * OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO + * @retval 0 if correct communication, else wrong communication + */ +uint32_t wm8994_SetOutputMode(uint16_t DeviceAddr, uint8_t Output) +{ + uint32_t counter = 0; + + switch (Output) + { + case OUTPUT_DEVICE_SPEAKER: + /* Enable DAC1 (Left), Enable DAC1 (Right), + Disable DAC2 (Left), Disable DAC2 (Right)*/ + counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0C0C); + + /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0000); + + /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0000); + + /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0002); + + /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0002); + break; + + case OUTPUT_DEVICE_HEADPHONE: + /* Disable DAC1 (Left), Disable DAC1 (Right), + Enable DAC2 (Left), Enable DAC2 (Right)*/ + counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303); + + /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001); + + /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001); + + /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0000); + + /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0000); + break; + + case OUTPUT_DEVICE_BOTH: + /* Enable DAC1 (Left), Enable DAC1 (Right), + also Enable DAC2 (Left), Enable DAC2 (Right)*/ + counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303 | 0x0C0C); + + /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001); + + /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001); + + /* Enable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0002); + + /* Enable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0002); + break; + + default: + /* Disable DAC1 (Left), Disable DAC1 (Right), + Enable DAC2 (Left), Enable DAC2 (Right)*/ + counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303); + + /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001); + + /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001); + + /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0000); + + /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ + counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0000); + break; + } + return counter; +} + +/** + * @brief Sets new frequency. + * @param DeviceAddr: Device address on communication Bus. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t wm8994_SetFrequency(uint16_t DeviceAddr, uint32_t AudioFreq) +{ + uint32_t counter = 0; + + /* Clock Configurations */ + switch (AudioFreq) + { + case AUDIO_FREQUENCY_8K: + /* AIF1 Sample Rate = 8 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0003); + break; + + case AUDIO_FREQUENCY_16K: + /* AIF1 Sample Rate = 16 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0033); + break; + + case AUDIO_FREQUENCY_32K: + /* AIF1 Sample Rate = 32 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0063); + break; + + case AUDIO_FREQUENCY_48K: + /* AIF1 Sample Rate = 48 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0083); + break; + + case AUDIO_FREQUENCY_96K: + /* AIF1 Sample Rate = 96 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x00A3); + break; + + case AUDIO_FREQUENCY_11K: + /* AIF1 Sample Rate = 11.025 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0013); + break; + + case AUDIO_FREQUENCY_22K: + /* AIF1 Sample Rate = 22.050 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0043); + break; + + case AUDIO_FREQUENCY_44K: + /* AIF1 Sample Rate = 44.1 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0073); + break; + + default: + /* AIF1 Sample Rate = 48 (KHz), ratio=256 */ + counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0083); + break; + } + return counter; +} + +/** + * @brief Resets wm8994 registers. + * @param DeviceAddr: Device address on communication Bus. + * @retval 0 if correct communication, else wrong communication + */ +uint32_t wm8994_Reset(uint16_t DeviceAddr) +{ + uint32_t counter = 0; + + /* Reset Codec by writing in 0x0000 address register */ + counter = CODEC_IO_Write(DeviceAddr, 0x0000, 0x0000); + outputEnabled = 0; + inputEnabled=0; + + return counter; +} + +/** + * @brief Writes/Read a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param Value: Data to be written + * @retval None + */ +static uint8_t CODEC_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value) +{ + uint32_t result = 0; + + AUDIO_IO_Write(Addr, Reg, Value); + +#ifdef VERIFY_WRITTENDATA + /* Verify that the data has been correctly written */ + result = (AUDIO_IO_Read(Addr, Reg) == Value)? 0:1; +#endif /* VERIFY_WRITTENDATA */ + + return result; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/Components/wm8994/wm8994.h b/src/port_stm32f7/common/bsp_drivers/Components/wm8994/wm8994.h new file mode 100644 index 00000000..90bd3895 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/Components/wm8994/wm8994.h @@ -0,0 +1,186 @@ +/** + ****************************************************************************** + * @file wm8994.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for the + * wm8994.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __WM8994_H +#define __WM8994_H + +/* Includes ------------------------------------------------------------------*/ +#include "../Common/audio.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup Component + * @{ + */ + +/** @addtogroup WM8994 + * @{ + */ + +/** @defgroup WM8994_Exported_Types + * @{ + */ + +/** + * @} + */ + +/** @defgroup WM8994_Exported_Constants + * @{ + */ + +/******************************************************************************/ +/*************************** Codec User defines ******************************/ +/******************************************************************************/ +/* Codec output DEVICE */ +#define OUTPUT_DEVICE_SPEAKER ((uint16_t)0x0001) +#define OUTPUT_DEVICE_HEADPHONE ((uint16_t)0x0002) +#define OUTPUT_DEVICE_BOTH ((uint16_t)0x0003) +#define OUTPUT_DEVICE_AUTO ((uint16_t)0x0004) +#define INPUT_DEVICE_DIGITAL_MICROPHONE_1 ((uint16_t)0x0100) +#define INPUT_DEVICE_DIGITAL_MICROPHONE_2 ((uint16_t)0x0200) +#define INPUT_DEVICE_INPUT_LINE_1 ((uint16_t)0x0300) +#define INPUT_DEVICE_INPUT_LINE_2 ((uint16_t)0x0400) +#define INPUT_DEVICE_DIGITAL_MIC1_MIC2 ((uint16_t)0x0800) + +/* Volume Levels values */ +#define DEFAULT_VOLMIN 0x00 +#define DEFAULT_VOLMAX 0xFF +#define DEFAULT_VOLSTEP 0x04 + +#define AUDIO_PAUSE 0 +#define AUDIO_RESUME 1 + +/* Codec POWER DOWN modes */ +#define CODEC_PDWN_HW 1 +#define CODEC_PDWN_SW 2 + +/* MUTE commands */ +#define AUDIO_MUTE_ON 1 +#define AUDIO_MUTE_OFF 0 + +/* AUDIO FREQUENCY */ +#define AUDIO_FREQUENCY_192K ((uint32_t)192000) +#define AUDIO_FREQUENCY_96K ((uint32_t)96000) +#define AUDIO_FREQUENCY_48K ((uint32_t)48000) +#define AUDIO_FREQUENCY_44K ((uint32_t)44100) +#define AUDIO_FREQUENCY_32K ((uint32_t)32000) +#define AUDIO_FREQUENCY_22K ((uint32_t)22050) +#define AUDIO_FREQUENCY_16K ((uint32_t)16000) +#define AUDIO_FREQUENCY_11K ((uint32_t)11025) +#define AUDIO_FREQUENCY_8K ((uint32_t)8000) + +#define VOLUME_CONVERT(Volume) (((Volume) > 100)? 100:((uint8_t)(((Volume) * 63) / 100))) +#define VOLUME_IN_CONVERT(Volume) (((Volume) >= 100)? 239:((uint8_t)(((Volume) * 240) / 100))) + +/******************************************************************************/ +/****************************** REGISTER MAPPING ******************************/ +/******************************************************************************/ +/** + * @brief WM8994 ID + */ +#define WM8994_ID 0x8994 + +/** + * @brief Device ID Register: Reading from this register will indicate device + * family ID 8994h + */ +#define WM8994_CHIPID_ADDR 0x00 + +/** + * @} + */ + +/** @defgroup WM8994_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup WM8994_Exported_Functions + * @{ + */ + +/*------------------------------------------------------------------------------ + Audio Codec functions +------------------------------------------------------------------------------*/ +/* High Layer codec functions */ +uint32_t wm8994_Init(uint16_t DeviceAddr, uint16_t OutputInputDevice, uint8_t Volume, uint32_t AudioFreq); +void wm8994_DeInit(void); +uint32_t wm8994_ReadID(uint16_t DeviceAddr); +uint32_t wm8994_Play(uint16_t DeviceAddr, uint16_t* pBuffer, uint16_t Size); +uint32_t wm8994_Pause(uint16_t DeviceAddr); +uint32_t wm8994_Resume(uint16_t DeviceAddr); +uint32_t wm8994_Stop(uint16_t DeviceAddr, uint32_t Cmd); +uint32_t wm8994_SetVolume(uint16_t DeviceAddr, uint8_t Volume); +uint32_t wm8994_SetMute(uint16_t DeviceAddr, uint32_t Cmd); +uint32_t wm8994_SetOutputMode(uint16_t DeviceAddr, uint8_t Output); +uint32_t wm8994_SetFrequency(uint16_t DeviceAddr, uint32_t AudioFreq); +uint32_t wm8994_Reset(uint16_t DeviceAddr); + +/* AUDIO IO functions */ +void AUDIO_IO_Init(void); +void AUDIO_IO_DeInit(void); +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value); +uint8_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg); +void AUDIO_IO_Delay(uint32_t Delay); + +/* Audio driver structure */ +extern AUDIO_DrvTypeDef wm8994_drv; + +#endif /* __WM8994_H */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/License.md b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/License.md new file mode 100644 index 00000000..9539743f --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/License.md @@ -0,0 +1,3 @@ +# Copyright (c) *2015* STMicroelectronics + +This software component is licensed by STMicroelectronics under the **BSD-3-Clause** license. You may not use this software except in compliance with this license. You may obtain a copy of the license [here](https://opensource.org/licenses/BSD-3-Clause). \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/Release_Notes.html new file mode 100644 index 00000000..06f8b1be --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/Release_Notes.html @@ -0,0 +1,797 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Release Notes for STM32746G-Discovery BSP Driver + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for STM32746G-Discovery BSP Driver

+

Copyright +2016 STMicroelectronics

+

+
+

 

+ + + + + + +

The BSP (Board Specific +Package) drivers are parts of the STM32Cube package based on the HAL +drivers and provide a set of high level APIs relative to the hardware +components and features in the evaluation boards, discovery kits and nucleo +boards coming with the STM32Cube package for a given STM32 serie.

+

The BSP drivers allow a quick access to the boards’ +services using high level APIs and without any specific configuration as the +link with the HAL and the external components is done in intrinsic within the drivers.
+

+

From project settings points of view, user has only +to add the necessary driver’s files in the workspace and call the needed +functions from examples. However some low level +configuration functions are weak and can be overridden by the applications if user +wants to change some BSP drivers default behavior.

+ + +

    Update History

+

V2.0.3 / 12-February-2021

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • stm32746g_discovery_lcd.c:
    • Remove GPIO PIN 13 (LCD VSYNC) configuration from BSP_LCD_MspInit() API to avoid conflict with stm32746g_discovery_ts.c driver.

V2.0.2 / 24-August-2017

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • stm32746g_discovery_lcd.c:
    • Fix compilation errors with SW4STM32 toolchain.
  • stm32746g_discovery.c:
    • Upgrade version to v2.0.2

V2.0.1 / 26-May-2017

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • Add general description of BSP drivers
    +
  • Add Dependencies section
    +
  • Support of PDSC
+ + + +

V2.0.0 / 30-December-2016

+ +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • stm32f746g_discovery_sd.c/.h:
    • Update BSP SD APIs following new HAL SD drivers implementation
    • Fix BlockSize to 512 bytes
      +
  • stm32f746g_discovery_audio.c/.h:
    • Update BSP_AUDIO_IN_Init parameters
      +
  • stm32f746g_discovery_lcd.c/.h:
    • Update BSP_LCD_ReadPixel to read correctely ARGB8888 and RGB888 pixels
  • stm32f746g_discovery_qspi.c/.h:
    • QSPI write operation improvement
    • Update CS High Time
    +
+
  • Notes:
    +
  • +
      +
    • These BSP drivers break the compatibility with previous versions.
    • +
    +
      +
    • If FatFs is required, "FatFS R0.11 ST modified 20161223" must be used with this version of BSP drivers.
    • +
    + +
+

V1.1.1 / 02-June-2016

+ + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • Update typos in drivers comments.

V1.1.0 / 22-April-2016

+ + + + + + + + + + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • Update overall drivers +by removing BSP_PPP_IRQHandler, BSP_PPP_DMA_TX_IRQHandler and BSP_PPP_DMA_RX_IRQHandler to +avoid possible conflict when the same Handler is used by different +IPs.
  • These Handlers should be +defined by user at application level, inducing a break of compatibility versus +V1.0.0 of the STM32F46G-Discovery BSP drivers
  • Update NVIC priority configuration to the lowest priority 0x0F in overall drivers
  • stm32f746g_discovery_camera.c:
    • Update BSP_CAMERA_Suspend() and BSP_CAMERA_Resume() APIs to use HAL API HAL_DCMI_Suspend() and HAL_DCMI_Resume()
  • stm32746g_discovery_lcd.c: Add the following APIs:
    • BSP_LCD_SetTransparency_NoReload()
    • BSP_LCD_SetLayerAddress_NoReload()
    • BSP_LCD_SetColorKeying_NoReload()
    • BSP_LCD_ResetColorKeying_NoReload()
    • BSP_LCD_SetLayerWindow_NoReload()
    • BSP_LCD_SetLayerVisible_NoReload()
    • BSP_LCD_Relaod()
+ +

V1.0.0 / 25-June-2015

+ + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • First official release +of the STM32746G-DISCO board BSP +drivers
  • +

Dependencies

+ + + + + + +
  • STM32F7xx_HAL_Driver V1.2.0
    +
  • BSP Common V4.0.1

License

+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery.c b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery.c new file mode 100644 index 00000000..916e3653 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery.c @@ -0,0 +1,902 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery.c + * @author MCD Application Team + * @brief This file provides a set of firmware functions to manage LEDs, + * push-buttons and COM ports available on STM32746G-Discovery + * board(MB1191) from STMicroelectronics. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_uart.c +- stm32f7xx_hal_i2c.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32746g_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_LOW_LEVEL STM32746G_DISCOVERY_LOW_LEVEL + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_LOW_LEVEL_Private_TypesDefinitions STM32746G_DISCOVERY_LOW_LEVEL Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_LOW_LEVEL_Private_Defines STM32746G_DISCOVERY_LOW_LEVEL Private Defines + * @{ + */ +/** + * @brief STM32746G DISCOVERY BSP Driver version number V2.0.2 + */ +#define __STM32746G_DISCO_BSP_VERSION_MAIN (0x02) /*!< [31:24] main version */ +#define __STM32746G_DISCO_BSP_VERSION_SUB1 (0x00) /*!< [23:16] sub1 version */ +#define __STM32746G_DISCO_BSP_VERSION_SUB2 (0x02) /*!< [15:8] sub2 version */ +#define __STM32746G_DISCO_BSP_VERSION_RC (0x00) /*!< [7:0] release candidate */ +#define __STM32746G_DISCO_BSP_VERSION ((__STM32746G_DISCO_BSP_VERSION_MAIN << 24)\ + |(__STM32746G_DISCO_BSP_VERSION_SUB1 << 16)\ + |(__STM32746G_DISCO_BSP_VERSION_SUB2 << 8 )\ + |(__STM32746G_DISCO_BSP_VERSION_RC)) +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_LOW_LEVEL_Private_Macros STM32746G_DISCOVERY_LOW_LEVEL Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_LOW_LEVEL_Private_Variables STM32746G_DISCOVERY_LOW_LEVEL Private Variables + * @{ + */ + +const uint32_t GPIO_PIN[LEDn] = {LED1_PIN}; + +GPIO_TypeDef* BUTTON_PORT[BUTTONn] = {WAKEUP_BUTTON_GPIO_PORT, + TAMPER_BUTTON_GPIO_PORT, + KEY_BUTTON_GPIO_PORT}; + +const uint16_t BUTTON_PIN[BUTTONn] = {WAKEUP_BUTTON_PIN, + TAMPER_BUTTON_PIN, + KEY_BUTTON_PIN}; + +const uint16_t BUTTON_IRQn[BUTTONn] = {WAKEUP_BUTTON_EXTI_IRQn, + TAMPER_BUTTON_EXTI_IRQn, + KEY_BUTTON_EXTI_IRQn}; + +USART_TypeDef* COM_USART[COMn] = {DISCOVERY_COM1}; + +GPIO_TypeDef* COM_TX_PORT[COMn] = {DISCOVERY_COM1_TX_GPIO_PORT}; + +GPIO_TypeDef* COM_RX_PORT[COMn] = {DISCOVERY_COM1_RX_GPIO_PORT}; + +const uint16_t COM_TX_PIN[COMn] = {DISCOVERY_COM1_TX_PIN}; + +const uint16_t COM_RX_PIN[COMn] = {DISCOVERY_COM1_RX_PIN}; + +const uint16_t COM_TX_AF[COMn] = {DISCOVERY_COM1_TX_AF}; + +const uint16_t COM_RX_AF[COMn] = {DISCOVERY_COM1_RX_AF}; + +static I2C_HandleTypeDef hI2cAudioHandler = {0}; +static I2C_HandleTypeDef hI2cExtHandler = {0}; + +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_LOW_LEVEL_Private_FunctionPrototypes STM32746G_DISCOVERY_LOW_LEVEL Private Function Prototypes + * @{ + */ +static void I2Cx_MspInit(I2C_HandleTypeDef *i2c_handler); +static void I2Cx_Init(I2C_HandleTypeDef *i2c_handler); + +static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static HAL_StatusTypeDef I2Cx_IsDeviceReady(I2C_HandleTypeDef *i2c_handler, uint16_t DevAddress, uint32_t Trials); +static void I2Cx_Error(I2C_HandleTypeDef *i2c_handler, uint8_t Addr); + +/* AUDIO IO functions */ +void AUDIO_IO_Init(void); +void AUDIO_IO_DeInit(void); +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value); +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg); +void AUDIO_IO_Delay(uint32_t Delay); + +/* TOUCHSCREEN IO functions */ +void TS_IO_Init(void); +void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg); +void TS_IO_Delay(uint32_t Delay); + +/* CAMERA IO functions */ +void CAMERA_IO_Init(void); +void CAMERA_Delay(uint32_t Delay); +void CAMERA_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +uint8_t CAMERA_IO_Read(uint8_t Addr, uint8_t Reg); + +/* I2C EEPROM IO function */ +void EEPROM_IO_Init(void); +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials); +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_LOW_LEVEL_Exported_Functions STM32746G_DISCOVERY_LOW_LEVELSTM32746G_DISCOVERY_LOW_LEVEL Exported Functions + * @{ + */ + + /** + * @brief This method returns the STM32746G DISCOVERY BSP Driver revision + * @retval version: 0xXYZR (8bits for each decimal, R for RC) + */ +uint32_t BSP_GetVersion(void) +{ + return __STM32746G_DISCO_BSP_VERSION; +} + +/** + * @brief Configures LED on GPIO. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED1 + * @retval None + */ +void BSP_LED_Init(Led_TypeDef Led) +{ + GPIO_InitTypeDef gpio_init_structure; + GPIO_TypeDef* gpio_led; + + if (Led == LED1) + { + gpio_led = LED1_GPIO_PORT; + /* Enable the GPIO_LED clock */ + LED1_GPIO_CLK_ENABLE(); + + /* Configure the GPIO_LED pin */ + gpio_init_structure.Pin = GPIO_PIN[Led]; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + + HAL_GPIO_Init(gpio_led, &gpio_init_structure); + + /* By default, turn off LED */ + HAL_GPIO_WritePin(gpio_led, GPIO_PIN[Led], GPIO_PIN_RESET); + } +} + +/** + * @brief DeInit LEDs. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED1 + * @note Led DeInit does not disable the GPIO clock + * @retval None + */ +void BSP_LED_DeInit(Led_TypeDef Led) +{ + GPIO_InitTypeDef gpio_init_structure; + GPIO_TypeDef* gpio_led; + + if (Led == LED1) + { + gpio_led = LED1_GPIO_PORT; + /* Turn off LED */ + HAL_GPIO_WritePin(gpio_led, GPIO_PIN[Led], GPIO_PIN_RESET); + /* Configure the GPIO_LED pin */ + gpio_init_structure.Pin = GPIO_PIN[Led]; + HAL_GPIO_DeInit(gpio_led, gpio_init_structure.Pin); + } +} + +/** + * @brief Turns selected LED On. + * @param Led: LED to be set on + * This parameter can be one of the following values: + * @arg LED1 + * @retval None + */ +void BSP_LED_On(Led_TypeDef Led) +{ + GPIO_TypeDef* gpio_led; + + if (Led == LED1) /* Switch On LED connected to GPIO */ + { + gpio_led = LED1_GPIO_PORT; + HAL_GPIO_WritePin(gpio_led, GPIO_PIN[Led], GPIO_PIN_SET); + } +} + +/** + * @brief Turns selected LED Off. + * @param Led: LED to be set off + * This parameter can be one of the following values: + * @arg LED1 + * @retval None + */ +void BSP_LED_Off(Led_TypeDef Led) +{ + GPIO_TypeDef* gpio_led; + + if (Led == LED1) /* Switch Off LED connected to GPIO */ + { + gpio_led = LED1_GPIO_PORT; + HAL_GPIO_WritePin(gpio_led, GPIO_PIN[Led], GPIO_PIN_RESET); + } +} + +/** + * @brief Toggles the selected LED. + * @param Led: LED to be toggled + * This parameter can be one of the following values: + * @arg LED1 + * @retval None + */ +void BSP_LED_Toggle(Led_TypeDef Led) +{ + GPIO_TypeDef* gpio_led; + + if (Led == LED1) /* Toggle LED connected to GPIO */ + { + gpio_led = LED1_GPIO_PORT; + HAL_GPIO_TogglePin(gpio_led, GPIO_PIN[Led]); + } +} + +/** + * @brief Configures button GPIO and EXTI Line. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_TAMPER: Tamper Push Button + * @arg BUTTON_KEY: Key Push Button + * @param ButtonMode: Button mode + * This parameter can be one of the following values: + * @arg BUTTON_MODE_GPIO: Button will be used as simple IO + * @arg BUTTON_MODE_EXTI: Button will be connected to EXTI line + * with interrupt generation capability + * @note On STM32746G-Discovery board, the three buttons (Wakeup, Tamper and key buttons) + * are mapped on the same push button named "User" + * on the board serigraphy. + * @retval None + */ +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef ButtonMode) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable the BUTTON clock */ + BUTTONx_GPIO_CLK_ENABLE(Button); + + if(ButtonMode == BUTTON_MODE_GPIO) + { + /* Configure Button pin as input */ + gpio_init_structure.Pin = BUTTON_PIN[Button]; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure); + } + + if(ButtonMode == BUTTON_MODE_EXTI) + { + /* Configure Button pin as input with External interrupt */ + gpio_init_structure.Pin = BUTTON_PIN[Button]; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + + if(Button != BUTTON_WAKEUP) + { + gpio_init_structure.Mode = GPIO_MODE_IT_FALLING; + } + else + { + gpio_init_structure.Mode = GPIO_MODE_IT_RISING; + } + + HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure); + + /* Enable and set Button EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(BUTTON_IRQn[Button]), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + } +} + +/** + * @brief Push Button DeInit. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_TAMPER: Tamper Push Button + * @arg BUTTON_KEY: Key Push Button + * @note On STM32746G-Discovery board, the three buttons (Wakeup, Tamper and key buttons) + * are mapped on the same push button named "User" + * on the board serigraphy. + * @note PB DeInit does not disable the GPIO clock + * @retval None + */ +void BSP_PB_DeInit(Button_TypeDef Button) +{ + GPIO_InitTypeDef gpio_init_structure; + + gpio_init_structure.Pin = BUTTON_PIN[Button]; + HAL_NVIC_DisableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + HAL_GPIO_DeInit(BUTTON_PORT[Button], gpio_init_structure.Pin); +} + + +/** + * @brief Returns the selected button state. + * @param Button: Button to be checked + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_TAMPER: Tamper Push Button + * @arg BUTTON_KEY: Key Push Button + * @note On STM32746G-Discovery board, the three buttons (Wakeup, Tamper and key buttons) + * are mapped on the same push button named "User" + * on the board serigraphy. + * @retval The Button GPIO pin value + */ +uint32_t BSP_PB_GetState(Button_TypeDef Button) +{ + return HAL_GPIO_ReadPin(BUTTON_PORT[Button], BUTTON_PIN[Button]); +} + +/** + * @brief Configures COM port. + * @param COM: COM port to be configured. + * This parameter can be one of the following values: + * @arg COM1 + * @arg COM2 + * @param huart: Pointer to a UART_HandleTypeDef structure that contains the + * configuration information for the specified USART peripheral. + * @retval None + */ +void BSP_COM_Init(COM_TypeDef COM, UART_HandleTypeDef *huart) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable GPIO clock */ + DISCOVERY_COMx_TX_GPIO_CLK_ENABLE(COM); + DISCOVERY_COMx_RX_GPIO_CLK_ENABLE(COM); + + /* Enable USART clock */ + DISCOVERY_COMx_CLK_ENABLE(COM); + + /* Configure USART Tx as alternate function */ + gpio_init_structure.Pin = COM_TX_PIN[COM]; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Alternate = COM_TX_AF[COM]; + HAL_GPIO_Init(COM_TX_PORT[COM], &gpio_init_structure); + + /* Configure USART Rx as alternate function */ + gpio_init_structure.Pin = COM_RX_PIN[COM]; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = COM_RX_AF[COM]; + HAL_GPIO_Init(COM_RX_PORT[COM], &gpio_init_structure); + + /* USART configuration */ + huart->Instance = COM_USART[COM]; + HAL_UART_Init(huart); +} + +/** + * @brief DeInit COM port. + * @param COM: COM port to be configured. + * This parameter can be one of the following values: + * @arg COM1 + * @arg COM2 + * @param huart: Pointer to a UART_HandleTypeDef structure that contains the + * configuration information for the specified USART peripheral. + * @retval None + */ +void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart) +{ + /* USART configuration */ + huart->Instance = COM_USART[COM]; + HAL_UART_DeInit(huart); + + /* Enable USART clock */ + DISCOVERY_COMx_CLK_DISABLE(COM); + + /* DeInit GPIO pins can be done in the application + (by surcharging this __weak function) */ + + /* GPIO pins clock, DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/******************************************************************************* + BUS OPERATIONS +*******************************************************************************/ + +/******************************* I2C Routines *********************************/ +/** + * @brief Initializes I2C MSP. + * @param i2c_handler : I2C handler + * @retval None + */ +static void I2Cx_MspInit(I2C_HandleTypeDef *i2c_handler) +{ + GPIO_InitTypeDef gpio_init_structure; + + if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cAudioHandler)) + { + /* AUDIO and LCD I2C MSP init */ + + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + DISCOVERY_AUDIO_I2Cx_SCL_SDA_GPIO_CLK_ENABLE(); + + /* Configure I2C Tx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_AUDIO_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = DISCOVERY_AUDIO_I2Cx_SCL_SDA_AF; + HAL_GPIO_Init(DISCOVERY_AUDIO_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C Rx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_AUDIO_I2Cx_SDA_PIN; + HAL_GPIO_Init(DISCOVERY_AUDIO_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + DISCOVERY_AUDIO_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + DISCOVERY_AUDIO_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + DISCOVERY_AUDIO_I2Cx_RELEASE_RESET(); + + /* Enable and set I2Cx Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_AUDIO_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_AUDIO_I2Cx_EV_IRQn); + + /* Enable and set I2Cx Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_AUDIO_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_AUDIO_I2Cx_ER_IRQn); + } + else + { + /* External, camera and Arduino connector I2C MSP init */ + + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_CLK_ENABLE(); + + /* Configure I2C Tx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_EXT_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = DISCOVERY_EXT_I2Cx_SCL_SDA_AF; + HAL_GPIO_Init(DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C Rx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_EXT_I2Cx_SDA_PIN; + HAL_GPIO_Init(DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + DISCOVERY_EXT_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + DISCOVERY_EXT_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + DISCOVERY_EXT_I2Cx_RELEASE_RESET(); + + /* Enable and set I2Cx Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_EXT_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_EXT_I2Cx_EV_IRQn); + + /* Enable and set I2Cx Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_EXT_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_EXT_I2Cx_ER_IRQn); + } +} + +/** + * @brief Initializes I2C HAL. + * @param i2c_handler : I2C handler + * @retval None + */ +static void I2Cx_Init(I2C_HandleTypeDef *i2c_handler) +{ + if(HAL_I2C_GetState(i2c_handler) == HAL_I2C_STATE_RESET) + { + if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cAudioHandler)) + { + /* Audio and LCD I2C configuration */ + i2c_handler->Instance = DISCOVERY_AUDIO_I2Cx; + } + else + { + /* External, camera and Arduino connector I2C configuration */ + i2c_handler->Instance = DISCOVERY_EXT_I2Cx; + } + i2c_handler->Init.Timing = DISCOVERY_I2Cx_TIMING; + i2c_handler->Init.OwnAddress1 = 0; + i2c_handler->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + i2c_handler->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + i2c_handler->Init.OwnAddress2 = 0; + i2c_handler->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + i2c_handler->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + + /* Init the I2C */ + I2Cx_MspInit(i2c_handler); + HAL_I2C_Init(i2c_handler); + } +} + +/** + * @brief Reads multiple data. + * @param i2c_handler : I2C handler + * @param Addr: I2C address + * @param Reg: Reg address + * @param MemAddress: Memory address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval Number of read data + */ +static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef *i2c_handler, + uint8_t Addr, + uint16_t Reg, + uint16_t MemAddress, + uint8_t *Buffer, + uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Read(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* I2C error occurred */ + I2Cx_Error(i2c_handler, Addr); + } + return status; +} + +/** + * @brief Writes a value in a register of the device through BUS in using DMA mode. + * @param i2c_handler : I2C handler + * @param Addr: Device address on BUS Bus. + * @param Reg: The target register address to write + * @param MemAddress: Memory address + * @param Buffer: The target register value to be written + * @param Length: buffer size to be written + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef *i2c_handler, + uint8_t Addr, + uint16_t Reg, + uint16_t MemAddress, + uint8_t *Buffer, + uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Write(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* Re-Initiaize the I2C Bus */ + I2Cx_Error(i2c_handler, Addr); + } + return status; +} + +/** + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param i2c_handler : I2C handler + * @param DevAddress: Target device address + * @param Trials: Number of trials + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_IsDeviceReady(I2C_HandleTypeDef *i2c_handler, uint16_t DevAddress, uint32_t Trials) +{ + return (HAL_I2C_IsDeviceReady(i2c_handler, DevAddress, Trials, 1000)); +} + +/** + * @brief Manages error callback by re-initializing I2C. + * @param i2c_handler : I2C handler + * @param Addr: I2C Address + * @retval None + */ +static void I2Cx_Error(I2C_HandleTypeDef *i2c_handler, uint8_t Addr) +{ + /* De-initialize the I2C communication bus */ + HAL_I2C_DeInit(i2c_handler); + + /* Re-Initialize the I2C communication bus */ + I2Cx_Init(i2c_handler); +} + +/******************************************************************************* + LINK OPERATIONS +*******************************************************************************/ + +/********************************* LINK AUDIO *********************************/ + +/** + * @brief Initializes Audio low level. + * @retval None + */ +void AUDIO_IO_Init(void) +{ + I2Cx_Init(&hI2cAudioHandler); +} + +/** + * @brief Deinitializes Audio low level. + * @retval None + */ +void AUDIO_IO_DeInit(void) +{ +} + +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param Value: Data to be written + * @retval None + */ +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value) +{ + uint16_t tmp = Value; + + Value = ((uint16_t)(tmp >> 8) & 0x00FF); + + Value |= ((uint16_t)(tmp << 8)& 0xFF00); + + I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_16BIT,(uint8_t*)&Value, 2); +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @retval Data to be read + */ +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg) +{ + uint16_t read_value = 0, tmp = 0; + + I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&read_value, 2); + + tmp = ((uint16_t)(read_value >> 8) & 0x00FF); + + tmp |= ((uint16_t)(read_value << 8)& 0xFF00); + + read_value = tmp; + + return read_value; +} + +/** + * @brief AUDIO Codec delay + * @param Delay: Delay in ms + * @retval None + */ +void AUDIO_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/********************************* LINK CAMERA ********************************/ + +/** + * @brief Initializes Camera low level. + * @retval None + */ +void CAMERA_IO_Init(void) +{ + I2Cx_Init(&hI2cExtHandler); +} + +/** + * @brief Camera writes single data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Value: Data to be written + * @retval None + */ +void CAMERA_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_WriteMultiple(&hI2cExtHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT,(uint8_t*)&Value, 1); +} + +/** + * @brief Camera reads single data. + * @param Addr: I2C address + * @param Reg: Register address + * @retval Read data + */ +uint8_t CAMERA_IO_Read(uint8_t Addr, uint8_t Reg) +{ + uint8_t read_value = 0; + + I2Cx_ReadMultiple(&hI2cExtHandler, Addr, Reg, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&read_value, 1); + + return read_value; +} + +/** + * @brief Camera delay + * @param Delay: Delay in ms + * @retval None + */ +void CAMERA_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/******************************** LINK I2C EEPROM *****************************/ + +/** + * @brief Initializes peripherals used by the I2C EEPROM driver. + * @retval None + */ +void EEPROM_IO_Init(void) +{ + I2Cx_Init(&hI2cExtHandler); +} + +/** + * @brief Write data to I2C EEPROM driver in using DMA channel. + * @param DevAddress: Target device address + * @param MemAddress: Internal memory address + * @param pBuffer: Pointer to data buffer + * @param BufferSize: Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize) +{ + return (I2Cx_WriteMultiple(&hI2cExtHandler, DevAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, pBuffer, BufferSize)); +} + +/** + * @brief Read data from I2C EEPROM driver in using DMA channel. + * @param DevAddress: Target device address + * @param MemAddress: Internal memory address + * @param pBuffer: Pointer to data buffer + * @param BufferSize: Amount of data to be read + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize) +{ + return (I2Cx_ReadMultiple(&hI2cExtHandler, DevAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, pBuffer, BufferSize)); +} + +/** + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param DevAddress: Target device address + * @param Trials: Number of trials + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials) +{ + return (I2Cx_IsDeviceReady(&hI2cExtHandler, DevAddress, Trials)); +} + +/********************************* LINK TOUCHSCREEN *********************************/ + +/** + * @brief Initializes Touchscreen low level. + * @retval None + */ +void TS_IO_Init(void) +{ + I2Cx_Init(&hI2cAudioHandler); +} + +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param Value: Data to be written + * @retval None + */ +void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT,(uint8_t*)&Value, 1); +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @retval Data to be read + */ +uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg) +{ + uint8_t read_value = 0; + + I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&read_value, 1); + + return read_value; +} + +/** + * @brief TS delay + * @param Delay: Delay in ms + * @retval None + */ +void TS_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery.h b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery.h new file mode 100644 index 00000000..c9f66d6c --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery.h @@ -0,0 +1,339 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery.h + * @author MCD Application Team + * @brief This file contains definitions for STM32746G_DISCOVERY's LEDs, + * push-buttons and COM ports hardware resources. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32746G_DISCOVERY_H +#define __STM32746G_DISCOVERY_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY_LOW_LEVEL + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_LOW_LEVEL_Exported_Types STM32746G_DISCOVERY_LOW_LEVEL Exported Types + * @{ + */ +typedef enum +{ +LED1 = 0, +LED_GREEN = LED1, +}Led_TypeDef; + +typedef enum +{ + BUTTON_WAKEUP = 0, + BUTTON_TAMPER = 1, + BUTTON_KEY = 2 +}Button_TypeDef; + +typedef enum +{ + BUTTON_MODE_GPIO = 0, + BUTTON_MODE_EXTI = 1 +}ButtonMode_TypeDef; + +typedef enum +{ + COM1 = 0, + COM2 = 1 +}COM_TypeDef; +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_LOW_LEVEL_Exported_Constants STM32746G_DISCOVERY_LOW_LEVEL Exported Constants + * @{ + */ + +/** + * @brief Define for STM32746G_DISCOVERY board + */ +#if !defined (USE_STM32746G_DISCO) + #define USE_STM32746G_DISCO +#endif + +/** @addtogroup STM32746G_DISCOVERY_LOW_LEVEL_LED + * @{ + */ + +#define LEDn ((uint8_t)1) + +#define LED1_GPIO_PORT GPIOI +#define LED1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define LED1_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define LED1_PIN GPIO_PIN_1 + +/** + * @} + */ + +/** @addtogroup STM32746G_DISCOVERY_LOW_LEVEL_BUTTON + * @{ + */ +#define BUTTONn ((uint8_t)3) + +/** + * @brief Wakeup push-button + */ +#define WAKEUP_BUTTON_PIN GPIO_PIN_11 +#define WAKEUP_BUTTON_GPIO_PORT GPIOI +#define WAKEUP_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define WAKEUP_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define WAKEUP_BUTTON_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief Tamper push-button + */ +#define TAMPER_BUTTON_PIN GPIO_PIN_11 +#define TAMPER_BUTTON_GPIO_PORT GPIOI +#define TAMPER_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define TAMPER_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define TAMPER_BUTTON_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief Key push-button + */ +#define KEY_BUTTON_PIN GPIO_PIN_11 +#define KEY_BUTTON_GPIO_PORT GPIOI +#define KEY_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define KEY_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define KEY_BUTTON_EXTI_IRQn EXTI15_10_IRQn + +#define BUTTONx_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == 0) WAKEUP_BUTTON_GPIO_CLK_ENABLE(); else\ + if((__INDEX__) == 1) TAMPER_BUTTON_GPIO_CLK_ENABLE(); else\ + KEY_BUTTON_GPIO_CLK_ENABLE(); } while(0) + +#define BUTTONx_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? WAKEUP_BUTTON_GPIO_CLK_DISABLE() :\ + ((__INDEX__) == 1) ? TAMPER_BUTTON_GPIO_CLK_DISABLE() : KEY_BUTTON_GPIO_CLK_DISABLE()) + +/** + * @} + */ + +/** @addtogroup STM32746G_DISCOVERY_LOW_LEVEL_SIGNAL + * @{ + */ +#define SIGNALn ((uint8_t)1) + +/** + * @brief SD-detect signal + */ +#define SD_DETECT_PIN GPIO_PIN_13 +#define SD_DETECT_GPIO_PORT GPIOC +#define SD_DETECT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define SD_DETECT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE() +#define SD_DETECT_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief Touch screen interrupt signal + */ +#define TS_INT_PIN GPIO_PIN_13 +#define TS_INT_GPIO_PORT GPIOI +#define TS_INT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define TS_INT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define TS_INT_EXTI_IRQn EXTI15_10_IRQn + +/** + * @} + */ + +/** @addtogroup STM32746G_DISCOVERY_LOW_LEVEL_COM + * @{ + */ +#define COMn ((uint8_t)1) + +/** + * @brief Definition for COM port1, connected to USART1 + */ +#define DISCOVERY_COM1 USART1 +#define DISCOVERY_COM1_CLK_ENABLE() __HAL_RCC_USART1_CLK_ENABLE() +#define DISCOVERY_COM1_CLK_DISABLE() __HAL_RCC_USART1_CLK_DISABLE() + +#define DISCOVERY_COM1_TX_PIN GPIO_PIN_9 +#define DISCOVERY_COM1_TX_GPIO_PORT GPIOA +#define DISCOVERY_COM1_TX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define DISCOVERY_COM1_TX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define DISCOVERY_COM1_TX_AF GPIO_AF7_USART1 + +#define DISCOVERY_COM1_RX_PIN GPIO_PIN_7 +#define DISCOVERY_COM1_RX_GPIO_PORT GPIOB +#define DISCOVERY_COM1_RX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define DISCOVERY_COM1_RX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE() +#define DISCOVERY_COM1_RX_AF GPIO_AF7_USART1 + +#define DISCOVERY_COM1_IRQn USART1_IRQn + +#define DISCOVERY_COMx_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) DISCOVERY_COM1_CLK_ENABLE(); } while(0) +#define DISCOVERY_COMx_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? DISCOVERY_COM1_CLK_DISABLE() : 0) + +#define DISCOVERY_COMx_TX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) DISCOVERY_COM1_TX_GPIO_CLK_ENABLE(); } while(0) +#define DISCOVERY_COMx_TX_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? DISCOVERY_COM1_TX_GPIO_CLK_DISABLE() : 0) + +#define DISCOVERY_COMx_RX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) DISCOVERY_COM1_RX_GPIO_CLK_ENABLE(); } while(0) +#define DISCOVERY_COMx_RX_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? DISCOVERY_COM1_RX_GPIO_CLK_DISABLE() : 0) + +/* Exported constant IO ------------------------------------------------------*/ + +#define LCD_I2C_ADDRESS ((uint16_t)0x70) +#define CAMERA_I2C_ADDRESS ((uint16_t)0x60) +#define AUDIO_I2C_ADDRESS ((uint16_t)0x34) +#define EEPROM_I2C_ADDRESS_A01 ((uint16_t)0xA0) +#define EEPROM_I2C_ADDRESS_A02 ((uint16_t)0xA6) +#define TS_I2C_ADDRESS ((uint16_t)0x70) + +/* I2C clock speed configuration (in Hz) + WARNING: + Make sure that this define is not already declared in other files (ie. + stm32746g_discovery.h file). It can be used in parallel by other modules. */ +#ifndef I2C_SPEED + #define I2C_SPEED ((uint32_t)100000) +#endif /* I2C_SPEED */ + +/* User can use this section to tailor I2Cx/I2Cx instance used and associated + resources */ +/* Definition for AUDIO and LCD I2Cx resources */ +#define DISCOVERY_AUDIO_I2Cx I2C3 +#define DISCOVERY_AUDIO_I2Cx_CLK_ENABLE() __HAL_RCC_I2C3_CLK_ENABLE() +#define DISCOVERY_AUDIO_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE() +#define DISCOVERY_AUDIO_I2Cx_SCL_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() + +#define DISCOVERY_AUDIO_I2Cx_FORCE_RESET() __HAL_RCC_I2C3_FORCE_RESET() +#define DISCOVERY_AUDIO_I2Cx_RELEASE_RESET() __HAL_RCC_I2C3_RELEASE_RESET() + +/* Definition for I2Cx Pins */ +#define DISCOVERY_AUDIO_I2Cx_SCL_PIN GPIO_PIN_7 +#define DISCOVERY_AUDIO_I2Cx_SCL_SDA_GPIO_PORT GPIOH +#define DISCOVERY_AUDIO_I2Cx_SCL_SDA_AF GPIO_AF4_I2C3 +#define DISCOVERY_AUDIO_I2Cx_SDA_PIN GPIO_PIN_8 + +/* I2C interrupt requests */ +#define DISCOVERY_AUDIO_I2Cx_EV_IRQn I2C3_EV_IRQn +#define DISCOVERY_AUDIO_I2Cx_ER_IRQn I2C3_ER_IRQn + +/* Definition for external, camera and Arduino connector I2Cx resources */ +#define DISCOVERY_EXT_I2Cx I2C1 +#define DISCOVERY_EXT_I2Cx_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE() +#define DISCOVERY_EXT_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE() +#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() + +#define DISCOVERY_EXT_I2Cx_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET() +#define DISCOVERY_EXT_I2Cx_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET() + +/* Definition for I2Cx Pins */ +#define DISCOVERY_EXT_I2Cx_SCL_PIN GPIO_PIN_8 +#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT GPIOB +#define DISCOVERY_EXT_I2Cx_SCL_SDA_AF GPIO_AF4_I2C1 +#define DISCOVERY_EXT_I2Cx_SDA_PIN GPIO_PIN_9 + +/* I2C interrupt requests */ +#define DISCOVERY_EXT_I2Cx_EV_IRQn I2C1_EV_IRQn +#define DISCOVERY_EXT_I2Cx_ER_IRQn I2C1_ER_IRQn + +/* I2C TIMING Register define when I2C clock source is SYSCLK */ +/* I2C TIMING is calculated from APB1 source clock = 50 MHz */ +/* Due to the big MOFSET capacity for adapting the camera level the rising time is very large (>1us) */ +/* 0x40912732 takes in account the big rising and aims a clock of 100khz */ +#ifndef DISCOVERY_I2Cx_TIMING +#define DISCOVERY_I2Cx_TIMING ((uint32_t)0x40912732) +#endif /* DISCOVERY_I2Cx_TIMING */ + +/** + * @} + */ + +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_LOW_LEVEL_Exported_Macros STM32746G_DISCOVERY_LOW_LEVEL Exported Macros + * @{ + */ +/** + * @} + */ + +/** @addtogroup STM32746G_DISCOVERY_LOW_LEVEL_Exported_Functions + * @{ + */ +uint32_t BSP_GetVersion(void); +void BSP_LED_Init(Led_TypeDef Led); +void BSP_LED_DeInit(Led_TypeDef Led); +void BSP_LED_On(Led_TypeDef Led); +void BSP_LED_Off(Led_TypeDef Led); +void BSP_LED_Toggle(Led_TypeDef Led); +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef ButtonMode); +void BSP_PB_DeInit(Button_TypeDef Button); +uint32_t BSP_PB_GetState(Button_TypeDef Button); +void BSP_COM_Init(COM_TypeDef COM, UART_HandleTypeDef *husart); +void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32746G_DISCOVERY_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_audio.c b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_audio.c new file mode 100644 index 00000000..4f64ebd5 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_audio.c @@ -0,0 +1,1380 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_audio.c + * @author MCD Application Team + * @brief This file provides the Audio driver for the STM32746G-Discovery board. + @verbatim + How To use this driver: + ----------------------- + + This driver supports STM32F7xx devices on STM32746G-Discovery (MB1191) board. + + Call the function BSP_AUDIO_OUT_Init( + OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, + OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH) + Volume : Initial volume to be set (0 is min (mute), 100 is max (100%) + AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...) + this parameter is relative to the audio file/stream type. + ) + This function configures all the hardware required for the audio application (codec, I2C, SAI, + GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK. + If the returned value is different from AUDIO_OK or the function is stuck then the communication with + the codec or the MFX has failed (try to un-plug the power or reset device in this case). + - OUTPUT_DEVICE_SPEAKER : only speaker will be set as output for the audio stream. + - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream. + - OUTPUT_DEVICE_BOTH : both Speaker and Headphone are used as outputs for the audio stream + at the same time. + Note. On STM32746G-Discovery SAI_DMA is configured in CIRCULAR mode. Due to this the application + does NOT need to call BSP_AUDIO_OUT_ChangeBuffer() to assure streaming. + + Call the function BSP_DISCOVERY_AUDIO_OUT_Play( + pBuffer: pointer to the audio data file address + Size : size of the buffer to be sent in Bytes + ) + to start playing (for the first time) from the audio file/stream. + + Call the function BSP_AUDIO_OUT_Pause() to pause playing + + Call the function BSP_AUDIO_OUT_Resume() to resume playing. + Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called + for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case). + Note. This function should be called only when the audio file is played or paused (not stopped). + + For each mode, you may need to implement the relative callback functions into your code. + The Callback functions are named AUDIO_OUT_XXX_CallBack() and only their prototypes are declared in + the stm32746g_discovery_audio.h file. (refer to the example for more details on the callbacks implementations) + + To Stop playing, to modify the volume level, the frequency, the audio frame slot, + the device output mode the mute or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(), + AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetAudioFrameSlot(), BSP_AUDIO_OUT_SetOutputMode(), + BSP_AUDIO_OUT_SetMute() and BSP_AUDIO_OUT_Stop(). + + The driver API and the callback functions are at the end of the stm32746g_discovery_audio.h file. + + Driver architecture: + -------------------- + + This driver provides the High Audio Layer: consists of the function API exported in the stm32746g_discovery_audio.h file + (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...) + + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/ + providing the audio file/stream. These functions are also included as local functions into + the stm32746g_discovery_audio_codec.c file (SAIx_Out_Init() and SAIx_Out_DeInit(), SAIx_In_Init() and SAIx_In_DeInit()) + + Known Limitations: + ------------------ + 1- If the TDM Format used to play in parallel 2 audio Stream (the first Stream is configured in codec SLOT0 and second + Stream in SLOT1) the Pause/Resume, volume and mute feature will control the both streams. + 2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, + File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file. + 3- Supports only Stereo audio streaming. + 4- Supports only 16-bits audio data size. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32746g_discovery.c +- stm32f7xx_hal_sai.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- wm8994.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32746g_discovery_audio.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO STM32746G_DISCOVERY AUDIO + * @brief This file includes the low layer driver for wm8994 Audio Codec + * available on STM32746G-Discovery board(MB1191). + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO_Private_Types STM32746G_DISCOVERY AUDIO Private Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO_Private_Defines STM32746G_DISCOVERY AUDIO Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO_Private_Macros STM32746G_DISCOVERY AUDIO Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO_Private_Variables STM32746G_DISCOVERY AUDIO Private Variables + * @{ + */ +AUDIO_DrvTypeDef *audio_drv; +SAI_HandleTypeDef haudio_out_sai={0}; +SAI_HandleTypeDef haudio_in_sai={0}; +TIM_HandleTypeDef haudio_tim; + +uint16_t __IO AudioInVolume = DEFAULT_AUDIO_IN_VOLUME; + +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO_Private_Function_Prototypes STM32746G_DISCOVERY AUDIO Private Function Prototypes + * @{ + */ +static void SAIx_Out_Init(uint32_t AudioFreq); +static void SAIx_Out_DeInit(void); +static void SAIx_In_Init(uint32_t SaiOutMode, uint32_t SlotActive, uint32_t AudioFreq); +static void SAIx_In_DeInit(void); +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO_OUT_Exported_Functions STM32746G_DISCOVERY AUDIO Out Exported Functions + * @{ + */ + +/** + * @brief Configures the audio peripherals. + * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * or OUTPUT_DEVICE_BOTH. + * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) + * @param AudioFreq: Audio frequency used to play the audio stream. + * @note The I2S PLL input clock must be done in the user application. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + + /* Disable SAI */ + SAIx_Out_DeInit(); + + /* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); + } + SAIx_Out_Init(AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq); + } + + return ret; +} + +/** + * @brief Starts playing audio stream from a data buffer for a determined size. + * @param pBuffer: Pointer to the buffer + * @param Size: Number of audio data in BYTES unit. + * In memory, first element is for left channel, second element is for right channel + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size) +{ + /* Call the audio Codec Play function */ + if(audio_drv->Play(AUDIO_I2C_ADDRESS, pBuffer, Size) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Update the Media layer and enable it for play */ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, DMA_MAX(Size / AUDIODATA_SIZE)); + + return AUDIO_OK; + } +} + +/** + * @brief Sends n-Bytes on the SAI interface. + * @param pData: pointer on data address + * @param Size: number of data to be written + * @retval None + */ +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size) +{ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pData, Size); +} + +/** + * @brief This function Pauses the audio file stream. In case + * of using DMA, the DMA Pause feature is used. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Pause(void) +{ + /* Call the Audio Codec Pause/Resume function */ + if(audio_drv->Pause(AUDIO_I2C_ADDRESS) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause function */ + HAL_SAI_DMAPause(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief This function Resumes the audio file stream. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Resume(void) +{ + /* Call the Audio Codec Pause/Resume function */ + if(audio_drv->Resume(AUDIO_I2C_ADDRESS) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause/resume function */ + HAL_SAI_DMAResume(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Stops audio playing and Power down the Audio Codec. + * @param Option: could be one of the following parameters + * - CODEC_PDWN_SW: for software power off (by writing registers). + * Then no need to reconfigure the Codec after power on. + * - CODEC_PDWN_HW: completely shut down the codec (physically). + * Then need to reconfigure the Codec after power on. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option) +{ + /* Call the Media layer stop function */ + HAL_SAI_DMAStop(&haudio_out_sai); + + /* Call Audio Codec Stop function */ + if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) + { + return AUDIO_ERROR; + } + else + { + if(Option == CODEC_PDWN_HW) + { + /* Wait at least 100us */ + HAL_Delay(1); + } + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Controls the current audio volume level. + * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for + * Mute and 100 for Max volume level). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume) +{ + /* Call the codec volume control function with converted volume value */ + if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Enables or disables the MUTE mode by software + * @param Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to + * unmute the codec and restore previous volume level. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd) +{ + /* Call the Codec Mute function */ + if(audio_drv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Switch dynamically (while audio file is played) the output target + * (speaker or headphone). + * @param Output: The audio output target: OUTPUT_DEVICE_SPEAKER, + * OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output) +{ + /* Call the Codec output device function */ + if(audio_drv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Updates the audio frequency. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frequency. + * @retval None + */ +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq) +{ + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frequency configuration */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Updates the Audio frame slot configuration. + * @param AudioFrameSlot: specifies the audio Frame slot + * This parameter can be one of the following values + * @arg CODEC_AUDIOFRAME_SLOT_0123 + * @arg CODEC_AUDIOFRAME_SLOT_02 + * @arg CODEC_AUDIOFRAME_SLOT_13 + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frame slot. + * @retval None + */ +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot) +{ + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frame slot configuration */ + haudio_out_sai.SlotInit.SlotActive = AudioFrameSlot; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Deinit the audio peripherals. + * @retval None + */ +void BSP_AUDIO_OUT_DeInit(void) +{ + SAIx_Out_DeInit(); + /* DeInit the SAI MSP : this __weak function can be rewritten by the application */ + BSP_AUDIO_OUT_MspDeInit(&haudio_out_sai, NULL); +} + +/** + * @brief Tx Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32746g_discovery_audio.h) */ + BSP_AUDIO_OUT_TransferComplete_CallBack(); +} + +/** + * @brief Tx Half Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32746g_discovery_audio.h) */ + BSP_AUDIO_OUT_HalfTransfer_CallBack(); +} + +/** + * @brief SAI error callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai) +{ + HAL_SAI_StateTypeDef audio_out_state; + HAL_SAI_StateTypeDef audio_in_state; + + audio_out_state = HAL_SAI_GetState(&haudio_out_sai); + audio_in_state = HAL_SAI_GetState(&haudio_in_sai); + + /* Determines if it is an audio out or audio in error */ + if ((audio_out_state == HAL_SAI_STATE_BUSY) || (audio_out_state == HAL_SAI_STATE_BUSY_TX)) + { + BSP_AUDIO_OUT_Error_CallBack(); + } + + if ((audio_in_state == HAL_SAI_STATE_BUSY) || (audio_in_state == HAL_SAI_STATE_BUSY_RX)) + { + BSP_AUDIO_IN_Error_CallBack(); + } +} + +/** + * @brief Manages the DMA full Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void) +{ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void) +{ +} + +/** + * @brief Manages the DMA FIFO error event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_Error_CallBack(void) +{ +} + +/** + * @brief Initializes BSP_AUDIO_OUT MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params) +{ + static DMA_HandleTypeDef hdma_sai_tx; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SAI clock */ + AUDIO_OUT_SAIx_CLK_ENABLE(); + + /* Enable GPIO clock */ + AUDIO_OUT_SAIx_MCLK_ENABLE(); + AUDIO_OUT_SAIx_SCK_SD_ENABLE(); + AUDIO_OUT_SAIx_FS_ENABLE(); + /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/ + gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_OUT_SAIx_FS_SD_MCLK_AF; + HAL_GPIO_Init(AUDIO_OUT_SAIx_FS_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_SCK_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_OUT_SAIx_SCK_AF; + HAL_GPIO_Init(AUDIO_OUT_SAIx_SCK_SD_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_SD_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_OUT_SAIx_FS_SD_MCLK_AF; + HAL_GPIO_Init(AUDIO_OUT_SAIx_SCK_SD_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_OUT_SAIx_FS_SD_MCLK_AF; + HAL_GPIO_Init(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, &gpio_init_structure); + + /* Enable the DMA clock */ + AUDIO_OUT_SAIx_DMAx_CLK_ENABLE(); + + if(hsai->Instance == AUDIO_OUT_SAIx) + { + /* Configure the hdma_saiTx handle parameters */ + hdma_sai_tx.Init.Channel = AUDIO_OUT_SAIx_DMAx_CHANNEL; + hdma_sai_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_sai_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sai_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sai_tx.Init.PeriphDataAlignment = AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE; + hdma_sai_tx.Init.MemDataAlignment = AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE; + hdma_sai_tx.Init.Mode = DMA_CIRCULAR; + hdma_sai_tx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_sai_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + hdma_sai_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sai_tx.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_sai_tx.Init.PeriphBurst = DMA_PBURST_SINGLE; + + hdma_sai_tx.Instance = AUDIO_OUT_SAIx_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsai, hdmatx, hdma_sai_tx); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_tx); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hdma_sai_tx); + } + + /* SAI DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_OUT_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ); +} + +/** + * @brief Deinitializes SAI MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* SAI DMA IRQ Channel deactivation */ + HAL_NVIC_DisableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ); + + if(hsai->Instance == AUDIO_OUT_SAIx) + { + /* Deinitialize the DMA stream */ + HAL_DMA_DeInit(hsai->hdmatx); + } + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(hsai); + + /* Deactives CODEC_SAI pins FS, SCK, MCK and SD by putting them in input mode */ + gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_FS_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_SCK_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_SCK_SD_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_SD_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_SCK_SD_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, gpio_init_structure.Pin); + + /* Disable SAI clock */ + AUDIO_OUT_SAIx_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Clock Config. + * @param hsai: might be required to set audio peripheral predivider if any. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @param Params + * @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params) +{ + RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; + + HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); + + /* Set the PLL configuration according to the audio frequency */ + if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) + { + /* Configure PLLI2S prescalers */ + /* PLLI2S_VCO: VCO_429M + I2S_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 429/2 = 214.5 Mhz + I2S_CLK_x = I2S_CLK(first level)/PLLI2SDIVQ = 214.5/19 = 11.289 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 429; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 2; + rcc_ex_clk_init_struct.PLLI2SDivQ = 19; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + + } + else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K), AUDIO_FREQUENCY_96K */ + { + /* I2S clock config + PLLI2S_VCO: VCO_344M + I2S_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 344/7 = 49.142 Mhz + I2S_CLK_x = I2S_CLK(first level)/PLLI2SDIVQ = 49.142/1 = 49.142 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 344; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 7; + rcc_ex_clk_init_struct.PLLI2SDivQ = 1; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + } +} + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Initializes the output Audio Codec audio interface (SAI). + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @note The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123 + * and user can update this configuration using + * @retval None + */ +static void SAIx_Out_Init(uint32_t AudioFreq) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + haudio_out_sai.Init.AudioMode = SAI_MODEMASTER_TX; + haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLED; + haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; + haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; + haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLED; + haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_out_sai.FrameInit.FrameLength = 64; + haudio_out_sai.FrameInit.ActiveFrameLength = 32; + haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot actives */ + haudio_out_sai.SlotInit.FirstBitOffset = 0; + haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_out_sai.SlotInit.SlotNumber = 4; + haudio_out_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_0123; + + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + + + +/** + * @brief Deinitializes the output Audio Codec audio interface (SAI). + * @retval None + */ +static void SAIx_Out_DeInit(void) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + HAL_SAI_DeInit(&haudio_out_sai); +} + +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO_Out_Private_Functions STM32746G_DISCOVERY_AUDIO Out Private Functions + * @{ + */ + +/** + * @brief Initializes wave recording. + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @param BitRes: Audio frequency to be configured. + * @param ChnlNbr: Channel number. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + return BSP_AUDIO_IN_InitEx(INPUT_DEVICE_DIGITAL_MICROPHONE_2, AudioFreq, BitRes, ChnlNbr); +} + +/** + * @brief Initializes wave recording. + * @param InputDevice: INPUT_DEVICE_DIGITAL_MICROPHONE_2 or INPUT_DEVICE_INPUT_LINE_1 + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @param BitRes: Audio frequency to be configured. + * @param ChnlNbr: Channel number. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + uint32_t slot_active; + + if ((InputDevice != INPUT_DEVICE_INPUT_LINE_1) && /* Only INPUT_LINE_1 and MICROPHONE_2 inputs supported */ + (InputDevice != INPUT_DEVICE_DIGITAL_MICROPHONE_2)) + { + ret = AUDIO_ERROR; + } + else + { + /* Disable SAI */ + SAIx_In_DeInit(); + + /* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_in_sai, AudioFreq, NULL); /* Clock config is shared between AUDIO IN and OUT */ + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from SAI peripheral to memory */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + if(HAL_SAI_GetState(&haudio_in_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_in_sai, NULL); /* Initialize GPIOs for SAI2 block A Master signals */ + BSP_AUDIO_IN_MspInit(&haudio_in_sai, NULL); + } + + /* Configure SAI in master RX mode : + * - SAI2_block_A in master RX mode + * - SAI2_block_B in slave RX mode synchronous from SAI2_block_A + */ + if (InputDevice == INPUT_DEVICE_DIGITAL_MICROPHONE_2) + { + slot_active = CODEC_AUDIOFRAME_SLOT_13; + } + else + { + slot_active = CODEC_AUDIOFRAME_SLOT_02; + } + SAIx_In_Init(SAI_MODEMASTER_RX, slot_active, AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, InputDevice, 100, AudioFreq); + } + } + return ret; +} + +/** + * @brief Initializes wave recording and playback in parallel. + * @param InputDevice: INPUT_DEVICE_DIGITAL_MICROPHONE_2 + * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * or OUTPUT_DEVICE_BOTH. + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @param BitRes: Audio frequency to be configured. + * @param ChnlNbr: Channel number. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_OUT_Init(uint16_t InputDevice, uint16_t OutputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + uint32_t slot_active; + + if (InputDevice != INPUT_DEVICE_DIGITAL_MICROPHONE_2) /* Only MICROPHONE_2 input supported */ + { + ret = AUDIO_ERROR; + } + else + { + /* Disable SAI */ + SAIx_In_DeInit(); + SAIx_Out_DeInit(); + + /* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_in_sai, AudioFreq, NULL); /* Clock config is shared between AUDIO IN and OUT */ + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from SAI peripheral to memory */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + if(HAL_SAI_GetState(&haudio_in_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_IN_MspInit(&haudio_in_sai, NULL); + } + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); + } + + /* Configure SAI in master mode : + * - SAI2_block_A in master TX mode + * - SAI2_block_B in slave RX mode synchronous from SAI2_block_A + */ + if (InputDevice == INPUT_DEVICE_DIGITAL_MICROPHONE_2) + { + slot_active = CODEC_AUDIOFRAME_SLOT_13; + } + else + { + slot_active = CODEC_AUDIOFRAME_SLOT_02; + } + SAIx_In_Init(SAI_MODEMASTER_TX, slot_active, AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, InputDevice | OutputDevice, 100, AudioFreq); + } + } + return ret; +} + + +/** + * @brief Starts audio recording. + * @param pbuf: Main buffer pointer for the recorded data storing + * @param size: size of the recorded buffer in number of elements (typically number of half-words) + * Be careful that it is not the same unit than BSP_AUDIO_OUT_Play function + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size) +{ + uint32_t ret = AUDIO_ERROR; + + /* Start the process receive DMA */ + HAL_SAI_Receive_DMA(&haudio_in_sai, (uint8_t*)pbuf, size); + + /* Return AUDIO_OK when all operations are correctly done */ + ret = AUDIO_OK; + + return ret; +} + +/** + * @brief Stops audio recording. + * @param Option: could be one of the following parameters + * - CODEC_PDWN_SW: for software power off (by writing registers). + * Then no need to reconfigure the Codec after power on. + * - CODEC_PDWN_HW: completely shut down the codec (physically). + * Then need to reconfigure the Codec after power on. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Stop(uint32_t Option) +{ + /* Call the Media layer stop function */ + HAL_SAI_DMAStop(&haudio_in_sai); + + /* Call Audio Codec Stop function */ + if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) + { + return AUDIO_ERROR; + } + else + { + if(Option == CODEC_PDWN_HW) + { + /* Wait at least 100us */ + HAL_Delay(1); + } + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Pauses the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Pause(void) +{ + /* Call the Media layer pause function */ + HAL_SAI_DMAPause(&haudio_in_sai); + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Resumes the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Resume(void) +{ + /* Call the Media layer pause/resume function */ + HAL_SAI_DMAResume(&haudio_in_sai); + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Controls the audio in volume level. + * @param Volume: Volume level in range 0(Mute)..80(+0dB)..100(+17.625dB) + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume) +{ + /* Call the codec volume control function with converted volume value */ + if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Set the Global variable AudioInVolume */ + AudioInVolume = Volume; + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Deinit the audio IN peripherals. + * @retval None + */ +void BSP_AUDIO_IN_DeInit(void) +{ + SAIx_In_DeInit(); + /* DeInit the SAI MSP : this __weak function can be rewritten by the application */ + BSP_AUDIO_IN_MspDeInit(&haudio_in_sai, NULL); +} + + /** + * @brief Rx Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ + BSP_AUDIO_IN_TransferComplete_CallBack(); +} + +/** + * @brief Rx Half Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32746g_discovery_audio.h) */ + BSP_AUDIO_IN_HalfTransfer_CallBack(); +} + +/** + * @brief User callback when record buffer is filled. + * @retval None + */ +__weak void BSP_AUDIO_IN_TransferComplete_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Audio IN Error callback function. + * @retval None + */ +__weak void BSP_AUDIO_IN_Error_CallBack(void) +{ + /* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +} + +/** + * @brief Initializes BSP_AUDIO_IN MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_IN_MspInit(SAI_HandleTypeDef *hsai, void *Params) +{ + static DMA_HandleTypeDef hdma_sai_rx; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SAI clock */ + AUDIO_IN_SAIx_CLK_ENABLE(); + + /* Enable SD GPIO clock */ + AUDIO_IN_SAIx_SD_ENABLE(); + /* CODEC_SAI pin configuration: SD pin */ + gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = AUDIO_IN_SAIx_SD_AF; + HAL_GPIO_Init(AUDIO_IN_SAIx_SD_GPIO_PORT, &gpio_init_structure); + + /* Enable Audio INT GPIO clock */ + AUDIO_IN_INT_GPIO_ENABLE(); + /* Audio INT pin configuration: input */ + gpio_init_structure.Pin = AUDIO_IN_INT_GPIO_PIN; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + HAL_GPIO_Init(AUDIO_IN_INT_GPIO_PORT, &gpio_init_structure); + + /* Enable the DMA clock */ + AUDIO_IN_SAIx_DMAx_CLK_ENABLE(); + + if(hsai->Instance == AUDIO_IN_SAIx) + { + /* Configure the hdma_sai_rx handle parameters */ + hdma_sai_rx.Init.Channel = AUDIO_IN_SAIx_DMAx_CHANNEL; + hdma_sai_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_sai_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sai_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sai_rx.Init.PeriphDataAlignment = AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE; + hdma_sai_rx.Init.MemDataAlignment = AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE; + hdma_sai_rx.Init.Mode = DMA_CIRCULAR; + hdma_sai_rx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_sai_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_sai_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sai_rx.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_sai_rx.Init.PeriphBurst = DMA_MBURST_SINGLE; + + hdma_sai_rx.Instance = AUDIO_IN_SAIx_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsai, hdmarx, hdma_sai_rx); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_rx); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hdma_sai_rx); + } + + /* SAI DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_IN_SAIx_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_IN_SAIx_DMAx_IRQ); + + /* Audio INT IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_IN_INT_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_IN_INT_IRQ); +} + +/** + * @brief DeInitializes BSP_AUDIO_IN MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_IN_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + static DMA_HandleTypeDef hdma_sai_rx; + + /* SAI IN DMA IRQ Channel deactivation */ + HAL_NVIC_DisableIRQ(AUDIO_IN_SAIx_DMAx_IRQ); + + if(hsai->Instance == AUDIO_IN_SAIx) + { + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_rx); + } + + /* Disable SAI block */ + __HAL_SAI_DISABLE(hsai); + + /* Disable pin: SD pin */ + gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN; + HAL_GPIO_DeInit(AUDIO_IN_SAIx_SD_GPIO_PORT, gpio_init_structure.Pin); + + /* Disable SAI clock */ + AUDIO_IN_SAIx_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Initializes the input Audio Codec audio interface (SAI). + * @param SaiOutMode: SAI_MODEMASTER_TX (for record and playback in parallel) + * or SAI_MODEMASTER_RX (for record only). + * @param SlotActive: CODEC_AUDIOFRAME_SLOT_02 or CODEC_AUDIOFRAME_SLOT_13 + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @retval None + */ +static void SAIx_In_Init(uint32_t SaiOutMode, uint32_t SlotActive, uint32_t AudioFreq) +{ + /* Initialize SAI2 block A in MASTER RX */ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + haudio_out_sai.Init.AudioMode = SaiOutMode; + haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLED; + haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; + haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; + haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLED; + haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_out_sai.FrameInit.FrameLength = 64; + haudio_out_sai.FrameInit.ActiveFrameLength = 32; + haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot actives */ + haudio_out_sai.SlotInit.FirstBitOffset = 0; + haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_out_sai.SlotInit.SlotNumber = 4; + haudio_out_sai.SlotInit.SlotActive = SlotActive; + + HAL_SAI_Init(&haudio_out_sai); + + /* Initialize SAI2 block B in SLAVE RX synchronous from SAI2 block A */ + /* Initialize the haudio_in_sai Instance parameter */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_in_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_in_sai.Init.AudioFrequency = AudioFreq; + haudio_in_sai.Init.AudioMode = SAI_MODESLAVE_RX; + haudio_in_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLED; + haudio_in_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_in_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_in_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_in_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; + haudio_in_sai.Init.Synchro = SAI_SYNCHRONOUS; + haudio_in_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLED; + haudio_in_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_in_sai.FrameInit.FrameLength = 64; + haudio_in_sai.FrameInit.ActiveFrameLength = 32; + haudio_in_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_in_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_in_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot active */ + haudio_in_sai.SlotInit.FirstBitOffset = 0; + haudio_in_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_in_sai.SlotInit.SlotNumber = 4; + haudio_in_sai.SlotInit.SlotActive = SlotActive; + + HAL_SAI_Init(&haudio_in_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); + + /* Enable SAI peripheral */ + __HAL_SAI_ENABLE(&haudio_in_sai); +} + + + +/** + * @brief Deinitializes the output Audio Codec audio interface (SAI). + * @retval None + */ +static void SAIx_In_DeInit(void) +{ + /* Initialize the haudio_in_sai Instance parameter */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(&haudio_in_sai); + + HAL_SAI_DeInit(&haudio_in_sai); +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_audio.h b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_audio.h new file mode 100644 index 00000000..4cf52c62 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_audio.h @@ -0,0 +1,293 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_audio.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32746g_discovery_audio.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32746G_DISCOVERY_AUDIO_H +#define __STM32746G_DISCOVERY_AUDIO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include audio component Driver */ +#include "../Components/wm8994/wm8994.h" +#include "stm32746g_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO STM32746G_DISCOVERY_AUDIO + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO_Exported_Types STM32746G_DISCOVERY_AUDIO Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO_Exported_Constants STM32746G_DISCOVERY_AUDIO Exported Constants + * @{ + */ + +/*------------------------------------------------------------------------------ + USER SAI defines parameters + -----------------------------------------------------------------------------*/ +/* CODEC_AudioFrame_SLOT_TDMMode + In W8994 codec the Audio frame contains 4 slots : TDM Mode + TDM format : + +------------------|------------------|--------------------|-------------------+ + | CODEC_SLOT0 Left | CODEC_SLOT1 Left | CODEC_SLOT0 Right | CODEC_SLOT1 Right | + +------------------------------------------------------------------------------+ + */ +/* To have 2 separate audio stream in Both headphone and speaker the 4 slot must be activated */ +#define CODEC_AUDIOFRAME_SLOT_0123 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_2 | SAI_SLOTACTIVE_3 +/* To have an audio stream in headphone only SAI Slot 0 and Slot 2 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_02 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_2 +/* To have an audio stream in speaker only SAI Slot 1 and Slot 3 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_13 SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_3 + +/* SAI OUT peripheral configuration defines */ +#define AUDIO_OUT_SAIx SAI2_Block_A +#define AUDIO_OUT_SAIx_CLK_ENABLE() __HAL_RCC_SAI2_CLK_ENABLE() +#define AUDIO_OUT_SAIx_CLK_DISABLE() __HAL_RCC_SAI2_CLK_DISABLE() +#define AUDIO_OUT_SAIx_SCK_AF GPIO_AF10_SAI2 +#define AUDIO_OUT_SAIx_FS_SD_MCLK_AF GPIO_AF10_SAI2 + +#define AUDIO_OUT_SAIx_MCLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define AUDIO_OUT_SAIx_MCLK_GPIO_PORT GPIOI +#define AUDIO_OUT_SAIx_MCLK_PIN GPIO_PIN_4 +#define AUDIO_OUT_SAIx_SCK_SD_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define AUDIO_OUT_SAIx_SCK_SD_GPIO_PORT GPIOI +#define AUDIO_OUT_SAIx_SCK_PIN GPIO_PIN_5 +#define AUDIO_OUT_SAIx_SD_PIN GPIO_PIN_6 +#define AUDIO_OUT_SAIx_FS_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define AUDIO_OUT_SAIx_FS_GPIO_PORT GPIOI +#define AUDIO_OUT_SAIx_FS_PIN GPIO_PIN_7 + +/* SAI DMA Stream definitions */ +#define AUDIO_OUT_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_OUT_SAIx_DMAx_STREAM DMA2_Stream4 +#define AUDIO_OUT_SAIx_DMAx_CHANNEL DMA_CHANNEL_3 +#define AUDIO_OUT_SAIx_DMAx_IRQ DMA2_Stream4_IRQn +#define AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD +#define AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD +#define DMA_MAX_SZE ((uint16_t)0xFFFF) + +#define AUDIO_OUT_SAIx_DMAx_IRQHandler DMA2_Stream4_IRQHandler + +/* Select the interrupt preemption priority for the DMA interrupt */ +#define AUDIO_OUT_IRQ_PREPRIO ((uint32_t)0x0E) /* Select the preemption priority level(0 is the highest) */ + +/*------------------------------------------------------------------------------ + AUDIO IN CONFIGURATION +------------------------------------------------------------------------------*/ +/* SAI IN peripheral configuration defines */ +#define AUDIO_IN_SAIx SAI2_Block_B +#define AUDIO_IN_SAIx_CLK_ENABLE() __HAL_RCC_SAI2_CLK_ENABLE() +#define AUDIO_IN_SAIx_CLK_DISABLE() __HAL_RCC_SAI2_CLK_DISABLE() +#define AUDIO_IN_SAIx_SD_AF GPIO_AF10_SAI2 + +#define AUDIO_IN_SAIx_SD_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE() +#define AUDIO_IN_SAIx_SD_GPIO_PORT GPIOG +#define AUDIO_IN_SAIx_SD_PIN GPIO_PIN_10 + +#define AUDIO_IN_INT_GPIO_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() +#define AUDIO_IN_INT_GPIO_PORT GPIOH +#define AUDIO_IN_INT_GPIO_PIN GPIO_PIN_15 +#define AUDIO_IN_INT_IRQ EXTI15_10_IRQn + +/* SAI DMA Stream definitions */ +#define AUDIO_IN_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_IN_SAIx_DMAx_STREAM DMA2_Stream7 +#define AUDIO_IN_SAIx_DMAx_CHANNEL DMA_CHANNEL_0 +#define AUDIO_IN_SAIx_DMAx_IRQ DMA2_Stream7_IRQn +#define AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD +#define AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD + +#define AUDIO_IN_SAIx_DMAx_IRQHandler DMA2_Stream7_IRQHandler +#define AUDIO_IN_INT_IRQHandler EXTI15_10_IRQHandler + +/* Select the interrupt preemption priority and subpriority for the IT/DMA interrupt */ +#define AUDIO_IN_IRQ_PREPRIO ((uint32_t)0x0F) /* Select the preemption priority level(0 is the highest) */ + +/*------------------------------------------------------------------------------ + CONFIGURATION: Audio Driver Configuration parameters +------------------------------------------------------------------------------*/ + +#define AUDIODATA_SIZE ((uint16_t)2) /* 16-bits audio data size */ + +/* Audio status definition */ +#define AUDIO_OK ((uint8_t)0) +#define AUDIO_ERROR ((uint8_t)1) +#define AUDIO_TIMEOUT ((uint8_t)2) + +/* AudioFreq * DataSize (2 bytes) * NumChannels (Stereo: 2) */ +#define DEFAULT_AUDIO_IN_FREQ I2S_AUDIOFREQ_16K +#define DEFAULT_AUDIO_IN_BIT_RESOLUTION ((uint8_t)16) +#define DEFAULT_AUDIO_IN_CHANNEL_NBR ((uint8_t)2) /* Mono = 1, Stereo = 2 */ +#define DEFAULT_AUDIO_IN_VOLUME ((uint16_t)64) + +/*------------------------------------------------------------------------------ + OPTIONAL Configuration defines parameters +------------------------------------------------------------------------------*/ + +/* Delay for the Codec to be correctly reset */ +#define CODEC_RESET_DELAY ((uint8_t)5) + + +/*------------------------------------------------------------------------------ + OUTPUT DEVICES definition +------------------------------------------------------------------------------*/ +/* Alias on existing output devices to adapt for 2 headphones output */ +#define OUTPUT_DEVICE_HEADPHONE1 OUTPUT_DEVICE_HEADPHONE +#define OUTPUT_DEVICE_HEADPHONE2 OUTPUT_DEVICE_SPEAKER /* Headphone2 is connected to Speaker output of the wm8994 */ + +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO_Exported_Variables STM32746G_DISCOVERY_AUDIO Exported Variables + * @{ + */ +extern __IO uint16_t AudioInVolume; + /** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO_Exported_Macros STM32746G_DISCOVERY_AUDIO Exported Macros + * @{ + */ +#define DMA_MAX(x) (((x) <= DMA_MAX_SZE)? (x):DMA_MAX_SZE) +/** + * @} + */ + +/** @addtogroup STM32746G_DISCOVERY_AUDIO_OUT_Exported_Functions + * @{ + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq); +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size); +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size); +uint8_t BSP_AUDIO_OUT_Pause(void); +uint8_t BSP_AUDIO_OUT_Resume(void); +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option); +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume); +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq); +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot); +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd); +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output); +void BSP_AUDIO_OUT_DeInit(void); + +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function is called when the requested data has been completely transferred.*/ +void BSP_AUDIO_OUT_TransferComplete_CallBack(void); + +/* This function is called when half of the requested buffer has been transferred. */ +void BSP_AUDIO_OUT_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_OUT_Error_CallBack(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params); +void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params); +void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); + +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_AUDIO_IN_Exported_Functions STM32746G_DISCOVERY_AUDIO_IN Exported Functions + * @{ + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_OUT_Init(uint16_t InputDevice, uint16_t OutputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_Record(uint16_t *pData, uint32_t Size); +uint8_t BSP_AUDIO_IN_Stop(uint32_t Option); +uint8_t BSP_AUDIO_IN_Pause(void); +uint8_t BSP_AUDIO_IN_Resume(void); +uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume); +void BSP_AUDIO_IN_DeInit(void); +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled to prepare the next + buffer pointer and its size. */ +void BSP_AUDIO_IN_TransferComplete_CallBack(void); +void BSP_AUDIO_IN_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_IN_Error_CallBack(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_IN_MspInit(SAI_HandleTypeDef *hsai, void *Params); +void BSP_AUDIO_IN_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32746G_DISCOVERY_AUDIO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_camera.c b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_camera.c new file mode 100644 index 00000000..e73977c8 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_camera.c @@ -0,0 +1,659 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_camera.c + * @author MCD Application Team + * @brief This file includes the driver for Camera modules mounted on + * STM32746G-Discovery board. + @verbatim + How to use this driver: + ------------------------ + - This driver is used to drive the camera. + - The OV9655 component driver MUST be included with this driver. + + Driver description: + ------------------- + + Initialization steps: + o Initialize the camera using the BSP_CAMERA_Init() function. + o Start the camera capture/snapshot using the CAMERA_Start() function. + o Suspend, resume or stop the camera capture using the following functions: + - BSP_CAMERA_Suspend() + - BSP_CAMERA_Resume() + - BSP_CAMERA_Stop() + + + Options + o Increase or decrease on the fly the brightness and/or contrast + using the following function: + - BSP_CAMERA_ContrastBrightnessConfig + o Add a special effect on the fly using the following functions: + - BSP_CAMERA_BlackWhiteConfig() + - BSP_CAMERA_ColorEffectConfig() + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32746g_discovery.c +- stm32f7xx_hal_dcmi.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- ov9655.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32746g_discovery_camera.h" +#include "stm32746g_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY_CAMERA + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_CAMERA_Private_TypesDefinitions STM32746G_DISCOVERY_CAMERA Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_CAMERA_Private_Defines STM32746G_DISCOVERY_CAMERA Private Defines + * @{ + */ +#define CAMERA_VGA_RES_X 640 +#define CAMERA_VGA_RES_Y 480 +#define CAMERA_480x272_RES_X 480 +#define CAMERA_480x272_RES_Y 272 +#define CAMERA_QVGA_RES_X 320 +#define CAMERA_QVGA_RES_Y 240 +#define CAMERA_QQVGA_RES_X 160 +#define CAMERA_QQVGA_RES_Y 120 +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_CAMERA_Private_Macros STM32746G_DISCOVERY_CAMERA Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_CAMERA_Private_Variables STM32746G_DISCOVERY_CAMERA Private Variables + * @{ + */ +DCMI_HandleTypeDef hDcmiHandler; +CAMERA_DrvTypeDef *camera_drv; +/* Camera current resolution naming (QQVGA, VGA, ...) */ +static uint32_t CameraCurrentResolution; + +/* Camera module I2C HW address */ +static uint32_t CameraHwAddress; +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_CAMERA_Private_FunctionPrototypes STM32746G_DISCOVERY_CAMERA Private Function Prototypes + * @{ + */ +static uint32_t GetSize(uint32_t resolution); +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_CAMERA_Exported_Functions STM32746G_DISCOVERY_CAMERA Exported Functions + * @{ + */ + +/** + * @brief Initializes the camera. + * @param Resolution : camera sensor requested resolution (x, y) : standard resolution + * naming QQVGA, QVGA, VGA ... + * @retval Camera status + */ +uint8_t BSP_CAMERA_Init(uint32_t Resolution) +{ + DCMI_HandleTypeDef *phdcmi; + uint8_t status = CAMERA_ERROR; + + /* Get the DCMI handle structure */ + phdcmi = &hDcmiHandler; + + /*** Configures the DCMI to interface with the camera module ***/ + /* DCMI configuration */ + phdcmi->Init.CaptureRate = DCMI_CR_ALL_FRAME; + phdcmi->Init.HSPolarity = DCMI_HSPOLARITY_LOW; + phdcmi->Init.SynchroMode = DCMI_SYNCHRO_HARDWARE; + phdcmi->Init.VSPolarity = DCMI_VSPOLARITY_HIGH; + phdcmi->Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B; + phdcmi->Init.PCKPolarity = DCMI_PCKPOLARITY_RISING; + phdcmi->Instance = DCMI; + + /* Power up camera */ + BSP_CAMERA_PwrUp(); + + /* Read ID of Camera module via I2C */ + if(ov9655_ReadID(CAMERA_I2C_ADDRESS) == OV9655_ID) + { + /* Initialize the camera driver structure */ + camera_drv = &ov9655_drv; + CameraHwAddress = CAMERA_I2C_ADDRESS; + + /* DCMI Initialization */ + BSP_CAMERA_MspInit(&hDcmiHandler, NULL); + HAL_DCMI_Init(phdcmi); + + /* Camera Module Initialization via I2C to the wanted 'Resolution' */ + if (Resolution == CAMERA_R480x272) + { /* For 480x272 resolution, the OV9655 sensor is set to VGA resolution + * as OV9655 doesn't supports 480x272 resolution, + * then DCMI is configured to output a 480x272 cropped window */ + camera_drv->Init(CameraHwAddress, CAMERA_R640x480); + HAL_DCMI_ConfigCROP(phdcmi, /* Crop in the middle of the VGA picture */ + (CAMERA_VGA_RES_X - CAMERA_480x272_RES_X)/2, + (CAMERA_VGA_RES_Y - CAMERA_480x272_RES_Y)/2, + (CAMERA_480x272_RES_X * 2) - 1, + CAMERA_480x272_RES_Y - 1); + HAL_DCMI_EnableCROP(phdcmi); + } + else + { + camera_drv->Init(CameraHwAddress, Resolution); + HAL_DCMI_DisableCROP(phdcmi); + } + + CameraCurrentResolution = Resolution; + + /* Return CAMERA_OK status */ + status = CAMERA_OK; + } + else + { + /* Return CAMERA_NOT_SUPPORTED status */ + status = CAMERA_NOT_SUPPORTED; + } + + return status; +} + +/** + * @brief DeInitializes the camera. + * @retval Camera status + */ +uint8_t BSP_CAMERA_DeInit(void) +{ + hDcmiHandler.Instance = DCMI; + + HAL_DCMI_DeInit(&hDcmiHandler); + BSP_CAMERA_MspDeInit(&hDcmiHandler, NULL); + return CAMERA_OK; +} + +/** + * @brief Starts the camera capture in continuous mode. + * @param buff: pointer to the camera output buffer + * @retval None + */ +void BSP_CAMERA_ContinuousStart(uint8_t *buff) +{ + /* Start the camera capture */ + HAL_DCMI_Start_DMA(&hDcmiHandler, DCMI_MODE_CONTINUOUS, (uint32_t)buff, GetSize(CameraCurrentResolution)); +} + +/** + * @brief Starts the camera capture in snapshot mode. + * @param buff: pointer to the camera output buffer + * @retval None + */ +void BSP_CAMERA_SnapshotStart(uint8_t *buff) +{ + /* Start the camera capture */ + HAL_DCMI_Start_DMA(&hDcmiHandler, DCMI_MODE_SNAPSHOT, (uint32_t)buff, GetSize(CameraCurrentResolution)); +} + +/** + * @brief Suspend the CAMERA capture + * @retval None + */ +void BSP_CAMERA_Suspend(void) +{ + /* Suspend the Camera Capture */ + HAL_DCMI_Suspend(&hDcmiHandler); +} + +/** + * @brief Resume the CAMERA capture + * @retval None + */ +void BSP_CAMERA_Resume(void) +{ + /* Start the Camera Capture */ + HAL_DCMI_Resume(&hDcmiHandler); +} + +/** + * @brief Stop the CAMERA capture + * @retval Camera status + */ +uint8_t BSP_CAMERA_Stop(void) +{ + uint8_t status = CAMERA_ERROR; + + if(HAL_DCMI_Stop(&hDcmiHandler) == HAL_OK) + { + status = CAMERA_OK; + } + + /* Set Camera in Power Down */ + BSP_CAMERA_PwrDown(); + + return status; +} + +/** + * @brief CANERA power up + * @retval None + */ +void BSP_CAMERA_PwrUp(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable GPIO clock */ + __HAL_RCC_GPIOH_CLK_ENABLE(); + + /*** Configure the GPIO ***/ + /* Configure DCMI GPIO as alternate function */ + gpio_init_structure.Pin = GPIO_PIN_13; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(GPIOH, &gpio_init_structure); + + /* De-assert the camera POWER_DOWN pin (active high) */ + HAL_GPIO_WritePin(GPIOH, GPIO_PIN_13, GPIO_PIN_RESET); + + HAL_Delay(3); /* POWER_DOWN de-asserted during 3ms */ +} + +/** + * @brief CAMERA power down + * @retval None + */ +void BSP_CAMERA_PwrDown(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable GPIO clock */ + __HAL_RCC_GPIOH_CLK_ENABLE(); + + /*** Configure the GPIO ***/ + /* Configure DCMI GPIO as alternate function */ + gpio_init_structure.Pin = GPIO_PIN_13; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(GPIOH, &gpio_init_structure); + + /* Assert the camera POWER_DOWN pin (active high) */ + HAL_GPIO_WritePin(GPIOH, GPIO_PIN_13, GPIO_PIN_SET); +} + +/** + * @brief Configures the camera contrast and brightness. + * @param contrast_level: Contrast level + * This parameter can be one of the following values: + * @arg CAMERA_CONTRAST_LEVEL4: for contrast +2 + * @arg CAMERA_CONTRAST_LEVEL3: for contrast +1 + * @arg CAMERA_CONTRAST_LEVEL2: for contrast 0 + * @arg CAMERA_CONTRAST_LEVEL1: for contrast -1 + * @arg CAMERA_CONTRAST_LEVEL0: for contrast -2 + * @param brightness_level: Contrast level + * This parameter can be one of the following values: + * @arg CAMERA_BRIGHTNESS_LEVEL4: for brightness +2 + * @arg CAMERA_BRIGHTNESS_LEVEL3: for brightness +1 + * @arg CAMERA_BRIGHTNESS_LEVEL2: for brightness 0 + * @arg CAMERA_BRIGHTNESS_LEVEL1: for brightness -1 + * @arg CAMERA_BRIGHTNESS_LEVEL0: for brightness -2 + * @retval None + */ +void BSP_CAMERA_ContrastBrightnessConfig(uint32_t contrast_level, uint32_t brightness_level) +{ + if(camera_drv->Config != NULL) + { + camera_drv->Config(CameraHwAddress, CAMERA_CONTRAST_BRIGHTNESS, contrast_level, brightness_level); + } +} + +/** + * @brief Configures the camera white balance. + * @param Mode: black_white mode + * This parameter can be one of the following values: + * @arg CAMERA_BLACK_WHITE_BW + * @arg CAMERA_BLACK_WHITE_NEGATIVE + * @arg CAMERA_BLACK_WHITE_BW_NEGATIVE + * @arg CAMERA_BLACK_WHITE_NORMAL + * @retval None + */ +void BSP_CAMERA_BlackWhiteConfig(uint32_t Mode) +{ + if(camera_drv->Config != NULL) + { + camera_drv->Config(CameraHwAddress, CAMERA_BLACK_WHITE, Mode, 0); + } +} + +/** + * @brief Configures the camera color effect. + * @param Effect: Color effect + * This parameter can be one of the following values: + * @arg CAMERA_COLOR_EFFECT_ANTIQUE + * @arg CAMERA_COLOR_EFFECT_BLUE + * @arg CAMERA_COLOR_EFFECT_GREEN + * @arg CAMERA_COLOR_EFFECT_RED + * @retval None + */ +void BSP_CAMERA_ColorEffectConfig(uint32_t Effect) +{ + if(camera_drv->Config != NULL) + { + camera_drv->Config(CameraHwAddress, CAMERA_COLOR_EFFECT, Effect, 0); + } +} + +/** + * @brief Get the capture size in pixels unit. + * @param resolution: the current resolution. + * @retval capture size in pixels unit. + */ +static uint32_t GetSize(uint32_t resolution) +{ + uint32_t size = 0; + + /* Get capture size */ + switch (resolution) + { + case CAMERA_R160x120: + { + size = 0x2580; + } + break; + case CAMERA_R320x240: + { + size = 0x9600; + } + break; + case CAMERA_R480x272: + { + size = 0xFF00; + } + break; + case CAMERA_R640x480: + { + size = 0x25800; + } + break; + default: + { + break; + } + } + + return size; +} + +/** + * @brief Initializes the DCMI MSP. + * @param hdcmi: HDMI handle + * @param Params + * @retval None + */ +__weak void BSP_CAMERA_MspInit(DCMI_HandleTypeDef *hdcmi, void *Params) +{ + static DMA_HandleTypeDef hdma_handler; + GPIO_InitTypeDef gpio_init_structure; + + /*** Enable peripherals and GPIO clocks ***/ + /* Enable DCMI clock */ + __HAL_RCC_DCMI_CLK_ENABLE(); + + /* Enable DMA2 clock */ + __HAL_RCC_DMA2_CLK_ENABLE(); + + /* Enable GPIO clocks */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + + /*** Configure the GPIO ***/ + /* Configure DCMI GPIO as alternate function */ + gpio_init_structure.Pin = GPIO_PIN_4 | GPIO_PIN_6; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOA, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_3; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_5 | GPIO_PIN_6; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_9; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 |\ + GPIO_PIN_12 | GPIO_PIN_14; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOH, &gpio_init_structure); + + /*** Configure the DMA ***/ + /* Set the parameters to be configured */ + hdma_handler.Init.Channel = DMA_CHANNEL_1; + hdma_handler.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_handler.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_handler.Init.MemInc = DMA_MINC_ENABLE; + hdma_handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + hdma_handler.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + hdma_handler.Init.Mode = DMA_CIRCULAR; + hdma_handler.Init.Priority = DMA_PRIORITY_HIGH; + hdma_handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_handler.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_handler.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_handler.Init.PeriphBurst = DMA_PBURST_SINGLE; + + hdma_handler.Instance = DMA2_Stream1; + + /* Associate the initialized DMA handle to the DCMI handle */ + __HAL_LINKDMA(hdcmi, DMA_Handle, hdma_handler); + + /*** Configure the NVIC for DCMI and DMA ***/ + /* NVIC configuration for DCMI transfer complete interrupt */ + HAL_NVIC_SetPriority(DCMI_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DCMI_IRQn); + + /* NVIC configuration for DMA2D transfer complete interrupt */ + HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn); + + /* Configure the DMA stream */ + HAL_DMA_Init(hdcmi->DMA_Handle); +} + + +/** + * @brief DeInitializes the DCMI MSP. + * @param hdcmi: HDMI handle + * @param Params + * @retval None + */ +__weak void BSP_CAMERA_MspDeInit(DCMI_HandleTypeDef *hdcmi, void *Params) +{ + /* Disable NVIC for DCMI transfer complete interrupt */ + HAL_NVIC_DisableIRQ(DCMI_IRQn); + + /* Disable NVIC for DMA2 transfer complete interrupt */ + HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn); + + /* Configure the DMA stream */ + HAL_DMA_DeInit(hdcmi->DMA_Handle); + + /* Disable DCMI clock */ + __HAL_RCC_DCMI_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Line event callback + * @param hdcmi: pointer to the DCMI handle + * @retval None + */ +void HAL_DCMI_LineEventCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_LineEventCallback(); +} + +/** + * @brief Line Event callback. + * @retval None + */ +__weak void BSP_CAMERA_LineEventCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_LineEventCallback could be implemented in the user file + */ +} + +/** + * @brief VSYNC event callback + * @param hdcmi: pointer to the DCMI handle + * @retval None + */ +void HAL_DCMI_VsyncEventCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_VsyncEventCallback(); +} + +/** + * @brief VSYNC Event callback. + * @retval None + */ +__weak void BSP_CAMERA_VsyncEventCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_VsyncEventCallback could be implemented in the user file + */ +} + +/** + * @brief Frame event callback + * @param hdcmi: pointer to the DCMI handle + * @retval None + */ +void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_FrameEventCallback(); +} + +/** + * @brief Frame Event callback. + * @retval None + */ +__weak void BSP_CAMERA_FrameEventCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_FrameEventCallback could be implemented in the user file + */ +} + +/** + * @brief Error callback + * @param hdcmi: pointer to the DCMI handle + * @retval None + */ +void HAL_DCMI_ErrorCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_ErrorCallback(); +} + +/** + * @brief Error callback. + * @retval None + */ +__weak void BSP_CAMERA_ErrorCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_ErrorCallback could be implemented in the user file + */ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_camera.h b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_camera.h new file mode 100644 index 00000000..fe8a7b3a --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_camera.h @@ -0,0 +1,147 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_camera.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32746g_discovery_camera.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32746G_DISCOVERY_CAMERA_H +#define __STM32746G_DISCOVERY_CAMERA_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include Camera component Driver */ +#include "../Components/ov9655/ov9655.h" +#include "stm32746g_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY_CAMERA + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_CAMERA_Exported_Types STM32746G_DISCOVERY_CAMERA Exported Types + * @{ + */ + +/** + * @brief Camera State structures definition + */ +typedef enum +{ + CAMERA_OK = 0x00, + CAMERA_ERROR = 0x01, + CAMERA_TIMEOUT = 0x02, + CAMERA_NOT_DETECTED = 0x03, + CAMERA_NOT_SUPPORTED = 0x04 + +} Camera_StatusTypeDef; + +#define RESOLUTION_R160x120 CAMERA_R160x120 /* QQVGA Resolution */ +#define RESOLUTION_R320x240 CAMERA_R320x240 /* QVGA Resolution */ +#define RESOLUTION_R480x272 CAMERA_R480x272 /* 480x272 Resolution */ +#define RESOLUTION_R640x480 CAMERA_R640x480 /* VGA Resolution */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_CAMERA_Exported_Constants STM32746G_DISCOVERY_CAMERA Exported Constants + * @{ + */ +#define BSP_CAMERA_IRQHandler DCMI_IRQHandler +#define BSP_CAMERA_DMA_IRQHandler DMA2_Stream1_IRQHandler + +/** + * @} + */ + +/** @addtogroup STM32746G_DISCOVERY_CAMERA_Exported_Functions + * @{ + */ +uint8_t BSP_CAMERA_Init(uint32_t Resolution); +uint8_t BSP_CAMERA_DeInit(void); +void BSP_CAMERA_ContinuousStart(uint8_t *buff); +void BSP_CAMERA_SnapshotStart(uint8_t *buff); +void BSP_CAMERA_Suspend(void); +void BSP_CAMERA_Resume(void); +uint8_t BSP_CAMERA_Stop(void); +void BSP_CAMERA_PwrUp(void); +void BSP_CAMERA_PwrDown(void); +void BSP_CAMERA_LineEventCallback(void); +void BSP_CAMERA_VsyncEventCallback(void); +void BSP_CAMERA_FrameEventCallback(void); +void BSP_CAMERA_ErrorCallback(void); + +/* Camera features functions prototype */ +void BSP_CAMERA_ContrastBrightnessConfig(uint32_t contrast_level, uint32_t brightness_level); +void BSP_CAMERA_BlackWhiteConfig(uint32_t Mode); +void BSP_CAMERA_ColorEffectConfig(uint32_t Effect); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_CAMERA_MspInit(DCMI_HandleTypeDef *hdcmi, void *Params); +void BSP_CAMERA_MspDeInit(DCMI_HandleTypeDef *hdcmi, void *Params); + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32746G_DISCOVERY_CAMERA_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_eeprom.c b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_eeprom.c new file mode 100644 index 00000000..4c4871c8 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_eeprom.c @@ -0,0 +1,477 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_eeprom.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage an I2C M24LR64 + * EEPROM memory. + @verbatim + To be able to use this driver, the switch EE_M24LR64 must be defined + in your toolchain compiler preprocessor + + =================================================================== + Notes: + - The I2C EEPROM memory (M24LR64) is available on separate daughter + board ANT7-M24LR-A, which is not provided with the STM32746G_DISCOVERY + board. + To use this driver you have to connect the ANT7-M24LR-A to CN3 + connector of STM32746G_DISCOVERY board. + =================================================================== + + It implements a high level communication layer for read and write + from/to this memory. The needed STM32F7xx hardware resources (I2C and + GPIO) are defined in stm32746g_discovery.h file, and the initialization is + performed in EEPROM_IO_Init() function declared in stm32746g_discovery.c + file. + You can easily tailor this driver to any other development board, + by just adapting the defines for hardware resources and + EEPROM_IO_Init() function. + + @note In this driver, basic read and write functions (BSP_EEPROM_ReadBuffer() + and BSP_EEPROM_WritePage()) use DMA mode to perform the data + transfer to/from EEPROM memory. + + @note Regarding BSP_EEPROM_WritePage(), it is an optimized function to perform + small write (less than 1 page) BUT the number of bytes (combined to write start address) must not + cross the EEPROM page boundary. This function can only writes into + the boundaries of an EEPROM page. + This function doesn't check on boundaries condition (in this driver + the function BSP_EEPROM_WriteBuffer() which calls BSP_EEPROM_WritePage() is + responsible of checking on Page boundaries). + + + +-----------------------------------------------------------------+ + | Pin assignment for M24LR64 EEPROM | + +---------------------------------------+-----------+-------------+ + | STM32F7xx I2C Pins | EEPROM | Pin | + +---------------------------------------+-----------+-------------+ + | . | E0(GND) | 1 (0V) | + | . | AC0 | 2 | + | . | AC1 | 3 | + | . | VSS | 4 (0V) | + | SDA | SDA | 5 | + | SCL | SCL | 6 | + | . | E1(GND) | 7 (0V) | + | . | VDD | 8 (3.3V) | + +---------------------------------------+-----------+-------------+ + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32746g_discovery.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32746g_discovery_eeprom.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY_EEPROM + * @brief This file includes the I2C EEPROM driver of STM32746G-Discovery board. + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_EEPROM_Private_Types STM32746G_DISCOVERY_EEPROM Private Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_EEPROM_Private_Defines STM32746G_DISCOVERY_EEPROM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_EEPROM_Private_Macros STM32746G_DISCOVERY_EEPROM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_EEPROM_Private_Variables STM32746G_DISCOVERY_EEPROM Private Variables + * @{ + */ +__IO uint16_t EEPROMAddress = 0; +__IO uint16_t EEPROMDataRead; +__IO uint8_t EEPROMDataWrite; +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_EEPROM_Private_Function_Prototypes STM32746G_DISCOVERY_EEPROM Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_EEPROM_Exported_Functions STM32746G_DISCOVERY_EEPROM Exported Functions + * @{ + */ + +/** + * @brief Initializes peripherals used by the I2C EEPROM driver. + * + * @note There are 2 different versions of M24LR64 (A01 & A02). + * Then try to connect on 1st one (EEPROM_I2C_ADDRESS_A01) + * and if problem, check the 2nd one (EEPROM_I2C_ADDRESS_A02) + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) + */ +uint32_t BSP_EEPROM_Init(void) +{ + /* I2C Initialization */ + EEPROM_IO_Init(); + + /* Select the EEPROM address for A01 and check if OK */ + EEPROMAddress = EEPROM_I2C_ADDRESS_A01; + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + /* Select the EEPROM address for A02 and check if OK */ + EEPROMAddress = EEPROM_I2C_ADDRESS_A02; + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + return EEPROM_FAIL; + } + } + return EEPROM_OK; +} + +/** + * @brief DeInitializes the EEPROM. + * @retval EEPROM state + */ +uint8_t BSP_EEPROM_DeInit(void) +{ + /* I2C won't be disabled because common to other functionalities */ + return EEPROM_OK; +} + +/** + * @brief Reads a block of data from the EEPROM. + * @param pBuffer: pointer to the buffer that receives the data read from + * the EEPROM. + * @param ReadAddr: EEPROM's internal address to start reading from. + * @param NumByteToRead: pointer to the variable holding number of bytes to + * be read from the EEPROM. + * + * @note The variable pointed by NumByteToRead is reset to 0 when all the + * data are read from the EEPROM. Application should monitor this + * variable in order know when the transfer is complete. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead) +{ + uint32_t buffersize = *NumByteToRead; + + /* Set the pointer to the Number of data to be read. This pointer will be used + by the DMA Transfer Completer interrupt Handler in order to reset the + variable to 0. User should check on this variable in order to know if the + DMA transfer has been complete or not. */ + EEPROMDataRead = *NumByteToRead; + + if(EEPROM_IO_ReadData(EEPROMAddress, ReadAddr, pBuffer, buffersize) != HAL_OK) + { + BSP_EEPROM_TIMEOUT_UserCallback(); + return EEPROM_FAIL; + } + + /* If all operations OK, return EEPROM_OK (0) */ + return EEPROM_OK; +} + +/** + * @brief Writes more than one byte to the EEPROM with a single WRITE cycle. + * + * @note The number of bytes (combined to write start address) must not + * cross the EEPROM page boundary. This function can only write into + * the boundaries of an EEPROM page. + * This function doesn't check on boundaries condition (in this driver + * the function BSP_EEPROM_WriteBuffer() which calls BSP_EEPROM_WritePage() is + * responsible of checking on Page boundaries). + * + * @param pBuffer: pointer to the buffer containing the data to be written to + * the EEPROM. + * @param WriteAddr: EEPROM's internal address to write to. + * @param NumByteToWrite: pointer to the variable holding number of bytes to + * be written into the EEPROM. + * + * @note The variable pointed by NumByteToWrite is reset to 0 when all the + * data are written to the EEPROM. Application should monitor this + * variable in order know when the transfer is complete. + * + * @note This function just configure the communication and enable the DMA + * channel to transfer data. Meanwhile, the user application may perform + * other tasks in parallel. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite) +{ + uint32_t buffersize = *NumByteToWrite; + uint32_t status = EEPROM_OK; + + /* Set the pointer to the Number of data to be written. This pointer will be used + by the DMA Transfer Completer interrupt Handler in order to reset the + variable to 0. User should check on this variable in order to know if the + DMA transfer has been complete or not. */ + EEPROMDataWrite = *NumByteToWrite; + + if(EEPROM_IO_WriteData(EEPROMAddress, WriteAddr, pBuffer, buffersize) != HAL_OK) + { + BSP_EEPROM_TIMEOUT_UserCallback(); + status = EEPROM_FAIL; + } + + if(BSP_EEPROM_WaitEepromStandbyState() != EEPROM_OK) + { + return EEPROM_FAIL; + } + + /* If all operations OK, return EEPROM_OK (0) */ + return status; +} + +/** + * @brief Writes buffer of data to the I2C EEPROM. + * @param pBuffer: pointer to the buffer containing the data to be written + * to the EEPROM. + * @param WriteAddr: EEPROM's internal address to write to. + * @param NumByteToWrite: number of bytes to write to the EEPROM. + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WriteBuffer(uint8_t *pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite) +{ + uint16_t numofpage = 0, numofsingle = 0, count = 0; + uint16_t addr = 0; + uint8_t dataindex = 0; + uint32_t status = EEPROM_OK; + + addr = WriteAddr % EEPROM_PAGESIZE; + count = EEPROM_PAGESIZE - addr; + numofpage = NumByteToWrite / EEPROM_PAGESIZE; + numofsingle = NumByteToWrite % EEPROM_PAGESIZE; + + /* If WriteAddr is EEPROM_PAGESIZE aligned */ + if(addr == 0) + { + /* If NumByteToWrite < EEPROM_PAGESIZE */ + if(numofpage == 0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + /* Start writing data */ + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + /* If NumByteToWrite > EEPROM_PAGESIZE */ + else + { + while(numofpage--) + { + /* Store the number of data to be written */ + dataindex = EEPROM_PAGESIZE; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + + WriteAddr += EEPROM_PAGESIZE; + pBuffer += EEPROM_PAGESIZE; + } + + if(numofsingle!=0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + } + /* If WriteAddr is not EEPROM_PAGESIZE aligned */ + else + { + /* If NumByteToWrite < EEPROM_PAGESIZE */ + if(numofpage== 0) + { + /* If the number of data to be written is more than the remaining space + in the current page: */ + if(NumByteToWrite > count) + { + /* Store the number of data to be written */ + dataindex = count; + /* Write the data contained in same page */ + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + + /* Store the number of data to be written */ + dataindex = (NumByteToWrite - count); + /* Write the remaining data in the following page */ + status = BSP_EEPROM_WritePage((uint8_t*)(pBuffer + count), (WriteAddr + count), (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + else + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + /* If NumByteToWrite > EEPROM_PAGESIZE */ + else + { + NumByteToWrite -= count; + numofpage = NumByteToWrite / EEPROM_PAGESIZE; + numofsingle = NumByteToWrite % EEPROM_PAGESIZE; + + if(count != 0) + { + /* Store the number of data to be written */ + dataindex = count; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + WriteAddr += count; + pBuffer += count; + } + + while(numofpage--) + { + /* Store the number of data to be written */ + dataindex = EEPROM_PAGESIZE; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + WriteAddr += EEPROM_PAGESIZE; + pBuffer += EEPROM_PAGESIZE; + } + if(numofsingle != 0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + } + + /* If all operations OK, return EEPROM_OK (0) */ + return EEPROM_OK; +} + +/** + * @brief Wait for EEPROM Standby state. + * + * @note This function allows to wait and check that EEPROM has finished the + * last operation. It is mostly used after Write operation: after receiving + * the buffer to be written, the EEPROM may need additional time to actually + * perform the write operation. During this time, it doesn't answer to + * I2C packets addressed to it. Once the write operation is complete + * the EEPROM responds to its address. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WaitEepromStandbyState(void) +{ + /* Check if the maximum allowed number of trials has bee reached */ + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + /* If the maximum number of trials has been reached, exit the function */ + BSP_EEPROM_TIMEOUT_UserCallback(); + return EEPROM_TIMEOUT; + } + return EEPROM_OK; +} + +/** + * @brief Basic management of the timeout situation. + * @retval None + */ +__weak void BSP_EEPROM_TIMEOUT_UserCallback(void) +{ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_eeprom.h b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_eeprom.h new file mode 100644 index 00000000..20c4cf31 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_eeprom.h @@ -0,0 +1,138 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_eeprom.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for + * the stm32746g_discovery_eeprom.c firmware driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32746G_DISCOVERY_EEPROM_H +#define __STM32746G_DISCOVERY_EEPROM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32746g_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY_EEPROM + * @brief This file includes the I2C EEPROM driver of STM32746G-Discovery board. + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_EEPROM_Exported_Types STM32746G_DISCOVERY_EEPROM Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_EEPROM_Exported_Constants STM32746G_DISCOVERY_EEPROM Exported Constants + * @{ + */ +/* EEPROM hardware address and page size */ +#define EEPROM_PAGESIZE ((uint8_t)4) +#define EEPROM_MAX_SIZE ((uint16_t)0x2000) /* 64Kbit */ + + +/* Maximum number of trials for EEPROM_WaitEepromStandbyState() function */ +#define EEPROM_MAX_TRIALS ((uint32_t)3000) + +#define EEPROM_OK ((uint32_t)0) +#define EEPROM_FAIL ((uint32_t)1) +#define EEPROM_TIMEOUT ((uint32_t)2) +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_EEPROM_Exported_Macros STM32746G_DISCOVERY_EEPROM Exported Macros + * @{ + */ +/** + * @} + */ + +/** @addtogroup STM32746G_DISCOVERY_EEPROM_Exported_Functions + * @{ + */ +uint32_t BSP_EEPROM_Init(void); +uint8_t BSP_EEPROM_DeInit(void); +uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead); +uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite); +uint32_t BSP_EEPROM_WriteBuffer(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite); +uint32_t BSP_EEPROM_WaitEepromStandbyState(void); + +/* USER Callbacks: This function is declared as __weak in EEPROM driver and + should be implemented into user application. + BSP_EEPROM_TIMEOUT_UserCallback() function is called whenever a timeout condition + occurs during communication (waiting on an event that doesn't occur, bus + errors, busy devices ...). */ +void BSP_EEPROM_TIMEOUT_UserCallback(void); + +/* Link function for I2C EEPROM peripheral */ +void EEPROM_IO_Init(void); +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32746G_DISCOVERY_EEPROM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_lcd.c b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_lcd.c new file mode 100644 index 00000000..527f3aac --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_lcd.c @@ -0,0 +1,1663 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_lcd.c + * @author MCD Application Team + * @brief This file includes the driver for Liquid Crystal Display (LCD) module + * mounted on STM32746G-Discovery board. + @verbatim + 1. How To use this driver: + -------------------------- + - This driver is used to drive directly an LCD TFT using the LTDC controller. + - This driver uses timing and setting for RK043FN48H LCD. + + 2. Driver description: + --------------------- + + Initialization steps: + o Initialize the LCD using the BSP_LCD_Init() function. + o Apply the Layer configuration using the BSP_LCD_LayerDefaultInit() function. + o Select the LCD layer to be used using the BSP_LCD_SelectLayer() function. + o Enable the LCD display using the BSP_LCD_DisplayOn() function. + + + Options + o Configure and enable the color keying functionality using the + BSP_LCD_SetColorKeying() function. + o Modify in the fly the transparency and/or the frame buffer address + using the following functions: + - BSP_LCD_SetTransparency() + - BSP_LCD_SetLayerAddress() + + + Display on LCD + o Clear the hole LCD using BSP_LCD_Clear() function or only one specified string + line using the BSP_LCD_ClearStringLine() function. + o Display a character on the specified line and column using the BSP_LCD_DisplayChar() + function or a complete string line using the BSP_LCD_DisplayStringAtLine() function. + o Display a string line on the specified position (x,y in pixel) and align mode + using the BSP_LCD_DisplayStringAtLine() function. + o Draw and fill a basic shapes (dot, line, rectangle, circle, ellipse, .. bitmap) + on LCD using the available set of functions. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32746g_discovery.c +- stm32746g_discovery_sdram.c +- stm32f7xx_hal_ltdc.c +- stm32f7xx_hal_ltdc_ex.c +- stm32f7xx_hal_dma2d.c +- stm32f7xx_hal_rcc_ex.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- rk043fn48h.h +- fonts.h +- font24.c +- font20.c +- font16.c +- font12.c +- font8.c" +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32746g_discovery_lcd.h" +#include "../../../Utilities/Fonts/fonts.h" +#include "../../../Utilities/Fonts/font24.c" +#include "../../../Utilities/Fonts/font20.c" +#include "../../../Utilities/Fonts/font16.c" +#include "../../../Utilities/Fonts/font12.c" +#include "../../../Utilities/Fonts/font8.c" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY_LCD + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_LCD_Private_TypesDefinitions STM32746G_DISCOVERY_LCD Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_LCD_Private_Defines STM32746G_DISCOVERY LCD Private Defines + * @{ + */ +#define POLY_X(Z) ((int32_t)((Points + Z)->X)) +#define POLY_Y(Z) ((int32_t)((Points + Z)->Y)) +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_LCD_Private_Macros STM32746G_DISCOVERY_LCD Private Macros + * @{ + */ +#define ABS(X) ((X) > 0 ? (X) : -(X)) +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_LCD_Private_Variables STM32746G_DISCOVERY_LCD Private Variables + * @{ + */ +LTDC_HandleTypeDef hLtdcHandler; +static DMA2D_HandleTypeDef hDma2dHandler; + +/* Default LCD configuration with LCD Layer 1 */ +static uint32_t ActiveLayer = 0; +static LCD_DrawPropTypeDef DrawProp[MAX_LAYER_NUMBER]; +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_LCD_Private_FunctionPrototypes STM32746G_DISCOVERY_LCD Private Function Prototypes + * @{ + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c); +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3); +static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex); +static void LL_ConvertLineToARGB8888(void * pSrc, void *pDst, uint32_t xSize, uint32_t ColorMode); +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_LCD_Exported_Functions STM32746G_DISCOVERY_LCD Exported Functions + * @{ + */ + +/** + * @brief Initializes the LCD. + * @retval LCD state + */ +uint8_t BSP_LCD_Init(void) +{ + /* Select the used LCD */ + + /* The RK043FN48H LCD 480x272 is selected */ + /* Timing Configuration */ + hLtdcHandler.Init.HorizontalSync = (RK043FN48H_HSYNC - 1); + hLtdcHandler.Init.VerticalSync = (RK043FN48H_VSYNC - 1); + hLtdcHandler.Init.AccumulatedHBP = (RK043FN48H_HSYNC + RK043FN48H_HBP - 1); + hLtdcHandler.Init.AccumulatedVBP = (RK043FN48H_VSYNC + RK043FN48H_VBP - 1); + hLtdcHandler.Init.AccumulatedActiveH = (RK043FN48H_HEIGHT + RK043FN48H_VSYNC + RK043FN48H_VBP - 1); + hLtdcHandler.Init.AccumulatedActiveW = (RK043FN48H_WIDTH + RK043FN48H_HSYNC + RK043FN48H_HBP - 1); + hLtdcHandler.Init.TotalHeigh = (RK043FN48H_HEIGHT + RK043FN48H_VSYNC + RK043FN48H_VBP + RK043FN48H_VFP - 1); + hLtdcHandler.Init.TotalWidth = (RK043FN48H_WIDTH + RK043FN48H_HSYNC + RK043FN48H_HBP + RK043FN48H_HFP - 1); + + /* LCD clock configuration */ + BSP_LCD_ClockConfig(&hLtdcHandler, NULL); + + /* Initialize the LCD pixel width and pixel height */ + hLtdcHandler.LayerCfg->ImageWidth = RK043FN48H_WIDTH; + hLtdcHandler.LayerCfg->ImageHeight = RK043FN48H_HEIGHT; + + /* Background value */ + hLtdcHandler.Init.Backcolor.Blue = 0; + hLtdcHandler.Init.Backcolor.Green = 0; + hLtdcHandler.Init.Backcolor.Red = 0; + + /* Polarity */ + hLtdcHandler.Init.HSPolarity = LTDC_HSPOLARITY_AL; + hLtdcHandler.Init.VSPolarity = LTDC_VSPOLARITY_AL; + hLtdcHandler.Init.DEPolarity = LTDC_DEPOLARITY_AL; + hLtdcHandler.Init.PCPolarity = LTDC_PCPOLARITY_IPC; + hLtdcHandler.Instance = LTDC; + + if(HAL_LTDC_GetState(&hLtdcHandler) == HAL_LTDC_STATE_RESET) + { + /* Initialize the LCD Msp: this __weak function can be rewritten by the application */ + BSP_LCD_MspInit(&hLtdcHandler, NULL); + } + HAL_LTDC_Init(&hLtdcHandler); + + /* Assert display enable LCD_DISP pin */ + HAL_GPIO_WritePin(LCD_DISP_GPIO_PORT, LCD_DISP_PIN, GPIO_PIN_SET); + + /* Assert backlight LCD_BL_CTRL pin */ + HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_PORT, LCD_BL_CTRL_PIN, GPIO_PIN_SET); + +#if !defined(DATA_IN_ExtSDRAM) + /* Initialize the SDRAM */ + BSP_SDRAM_Init(); +#endif + + /* Initialize the font */ + BSP_LCD_SetFont(&LCD_DEFAULT_FONT); + + return LCD_OK; +} + +/** + * @brief DeInitializes the LCD. + * @retval LCD state + */ +uint8_t BSP_LCD_DeInit(void) +{ + /* Initialize the hLtdcHandler Instance parameter */ + hLtdcHandler.Instance = LTDC; + + /* Disable LTDC block */ + __HAL_LTDC_DISABLE(&hLtdcHandler); + + /* DeInit the LTDC */ + HAL_LTDC_DeInit(&hLtdcHandler); + + /* DeInit the LTDC MSP : this __weak function can be rewritten by the application */ + BSP_LCD_MspDeInit(&hLtdcHandler, NULL); + + return LCD_OK; +} + +/** + * @brief Gets the LCD X size. + * @retval Used LCD X size + */ +uint32_t BSP_LCD_GetXSize(void) +{ + return hLtdcHandler.LayerCfg[ActiveLayer].ImageWidth; +} + +/** + * @brief Gets the LCD Y size. + * @retval Used LCD Y size + */ +uint32_t BSP_LCD_GetYSize(void) +{ + return hLtdcHandler.LayerCfg[ActiveLayer].ImageHeight; +} + +/** + * @brief Set the LCD X size. + * @param imageWidthPixels : image width in pixels unit + * @retval None + */ +void BSP_LCD_SetXSize(uint32_t imageWidthPixels) +{ + hLtdcHandler.LayerCfg[ActiveLayer].ImageWidth = imageWidthPixels; +} + +/** + * @brief Set the LCD Y size. + * @param imageHeightPixels : image height in lines unit + * @retval None + */ +void BSP_LCD_SetYSize(uint32_t imageHeightPixels) +{ + hLtdcHandler.LayerCfg[ActiveLayer].ImageHeight = imageHeightPixels; +} + +/** + * @brief Initializes the LCD layer in ARGB8888 format (32 bits per pixel). + * @param LayerIndex: Layer foreground or background + * @param FB_Address: Layer frame buffer + * @retval None + */ +void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) +{ + LCD_LayerCfgTypeDef layer_cfg; + + /* Layer Init */ + layer_cfg.WindowX0 = 0; + layer_cfg.WindowX1 = BSP_LCD_GetXSize(); + layer_cfg.WindowY0 = 0; + layer_cfg.WindowY1 = BSP_LCD_GetYSize(); + layer_cfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888; + layer_cfg.FBStartAdress = FB_Address; + layer_cfg.Alpha = 255; + layer_cfg.Alpha0 = 0; + layer_cfg.Backcolor.Blue = 0; + layer_cfg.Backcolor.Green = 0; + layer_cfg.Backcolor.Red = 0; + layer_cfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; + layer_cfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; + layer_cfg.ImageWidth = BSP_LCD_GetXSize(); + layer_cfg.ImageHeight = BSP_LCD_GetYSize(); + + HAL_LTDC_ConfigLayer(&hLtdcHandler, &layer_cfg, LayerIndex); + + DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE; + DrawProp[LayerIndex].pFont = &Font24; + DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK; +} + +/** + * @brief Initializes the LCD layer in RGB565 format (16 bits per pixel). + * @param LayerIndex: Layer foreground or background + * @param FB_Address: Layer frame buffer + * @retval None + */ +void BSP_LCD_LayerRgb565Init(uint16_t LayerIndex, uint32_t FB_Address) +{ + LCD_LayerCfgTypeDef layer_cfg; + + /* Layer Init */ + layer_cfg.WindowX0 = 0; + layer_cfg.WindowX1 = BSP_LCD_GetXSize(); + layer_cfg.WindowY0 = 0; + layer_cfg.WindowY1 = BSP_LCD_GetYSize(); + layer_cfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; + layer_cfg.FBStartAdress = FB_Address; + layer_cfg.Alpha = 255; + layer_cfg.Alpha0 = 0; + layer_cfg.Backcolor.Blue = 0; + layer_cfg.Backcolor.Green = 0; + layer_cfg.Backcolor.Red = 0; + layer_cfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; + layer_cfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; + layer_cfg.ImageWidth = BSP_LCD_GetXSize(); + layer_cfg.ImageHeight = BSP_LCD_GetYSize(); + + HAL_LTDC_ConfigLayer(&hLtdcHandler, &layer_cfg, LayerIndex); + + DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE; + DrawProp[LayerIndex].pFont = &Font24; + DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK; +} + +/** + * @brief Selects the LCD Layer. + * @param LayerIndex: Layer foreground or background + * @retval None + */ +void BSP_LCD_SelectLayer(uint32_t LayerIndex) +{ + ActiveLayer = LayerIndex; +} + +/** + * @brief Sets an LCD Layer visible + * @param LayerIndex: Visible Layer + * @param State: New state of the specified layer + * This parameter can be one of the following values: + * @arg ENABLE + * @arg DISABLE + * @retval None + */ +void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState State) +{ + if(State == ENABLE) + { + __HAL_LTDC_LAYER_ENABLE(&hLtdcHandler, LayerIndex); + } + else + { + __HAL_LTDC_LAYER_DISABLE(&hLtdcHandler, LayerIndex); + } + __HAL_LTDC_RELOAD_CONFIG(&hLtdcHandler); +} + +/** + * @brief Sets an LCD Layer visible without reloading. + * @param LayerIndex: Visible Layer + * @param State: New state of the specified layer + * This parameter can be one of the following values: + * @arg ENABLE + * @arg DISABLE + * @retval None + */ +void BSP_LCD_SetLayerVisible_NoReload(uint32_t LayerIndex, FunctionalState State) +{ + if(State == ENABLE) + { + __HAL_LTDC_LAYER_ENABLE(&hLtdcHandler, LayerIndex); + } + else + { + __HAL_LTDC_LAYER_DISABLE(&hLtdcHandler, LayerIndex); + } + /* Do not Sets the Reload */ +} + +/** + * @brief Configures the transparency. + * @param LayerIndex: Layer foreground or background. + * @param Transparency: Transparency + * This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF + * @retval None + */ +void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency) +{ + HAL_LTDC_SetAlpha(&hLtdcHandler, Transparency, LayerIndex); +} + +/** + * @brief Configures the transparency without reloading. + * @param LayerIndex: Layer foreground or background. + * @param Transparency: Transparency + * This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF + * @retval None + */ +void BSP_LCD_SetTransparency_NoReload(uint32_t LayerIndex, uint8_t Transparency) +{ + HAL_LTDC_SetAlpha_NoReload(&hLtdcHandler, Transparency, LayerIndex); +} + +/** + * @brief Sets an LCD layer frame buffer address. + * @param LayerIndex: Layer foreground or background + * @param Address: New LCD frame buffer value + * @retval None + */ +void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address) +{ + HAL_LTDC_SetAddress(&hLtdcHandler, Address, LayerIndex); +} + +/** + * @brief Sets an LCD layer frame buffer address without reloading. + * @param LayerIndex: Layer foreground or background + * @param Address: New LCD frame buffer value + * @retval None + */ +void BSP_LCD_SetLayerAddress_NoReload(uint32_t LayerIndex, uint32_t Address) +{ + HAL_LTDC_SetAddress_NoReload(&hLtdcHandler, Address, LayerIndex); +} + +/** + * @brief Sets display window. + * @param LayerIndex: Layer index + * @param Xpos: LCD X position + * @param Ypos: LCD Y position + * @param Width: LCD window width + * @param Height: LCD window height + * @retval None + */ +void BSP_LCD_SetLayerWindow(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Reconfigure the layer size */ + HAL_LTDC_SetWindowSize(&hLtdcHandler, Width, Height, LayerIndex); + + /* Reconfigure the layer position */ + HAL_LTDC_SetWindowPosition(&hLtdcHandler, Xpos, Ypos, LayerIndex); +} + +/** + * @brief Sets display window without reloading. + * @param LayerIndex: Layer index + * @param Xpos: LCD X position + * @param Ypos: LCD Y position + * @param Width: LCD window width + * @param Height: LCD window height + * @retval None + */ +void BSP_LCD_SetLayerWindow_NoReload(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Reconfigure the layer size */ + HAL_LTDC_SetWindowSize_NoReload(&hLtdcHandler, Width, Height, LayerIndex); + + /* Reconfigure the layer position */ + HAL_LTDC_SetWindowPosition_NoReload(&hLtdcHandler, Xpos, Ypos, LayerIndex); +} + +/** + * @brief Configures and sets the color keying. + * @param LayerIndex: Layer foreground or background + * @param RGBValue: Color reference + * @retval None + */ +void BSP_LCD_SetColorKeying(uint32_t LayerIndex, uint32_t RGBValue) +{ + /* Configure and Enable the color Keying for LCD Layer */ + HAL_LTDC_ConfigColorKeying(&hLtdcHandler, RGBValue, LayerIndex); + HAL_LTDC_EnableColorKeying(&hLtdcHandler, LayerIndex); +} + +/** + * @brief Configures and sets the color keying without reloading. + * @param LayerIndex: Layer foreground or background + * @param RGBValue: Color reference + * @retval None + */ +void BSP_LCD_SetColorKeying_NoReload(uint32_t LayerIndex, uint32_t RGBValue) +{ + /* Configure and Enable the color Keying for LCD Layer */ + HAL_LTDC_ConfigColorKeying_NoReload(&hLtdcHandler, RGBValue, LayerIndex); + HAL_LTDC_EnableColorKeying_NoReload(&hLtdcHandler, LayerIndex); +} + +/** + * @brief Disables the color keying. + * @param LayerIndex: Layer foreground or background + * @retval None + */ +void BSP_LCD_ResetColorKeying(uint32_t LayerIndex) +{ + /* Disable the color Keying for LCD Layer */ + HAL_LTDC_DisableColorKeying(&hLtdcHandler, LayerIndex); +} + +/** + * @brief Disables the color keying without reloading. + * @param LayerIndex: Layer foreground or background + * @retval None + */ +void BSP_LCD_ResetColorKeying_NoReload(uint32_t LayerIndex) +{ + /* Disable the color Keying for LCD Layer */ + HAL_LTDC_DisableColorKeying_NoReload(&hLtdcHandler, LayerIndex); +} + +/** + * @brief Disables the color keying without reloading. + * @param ReloadType: can be one of the following values + * - LCD_RELOAD_IMMEDIATE + * - LCD_RELOAD_VERTICAL_BLANKING + * @retval None + */ +void BSP_LCD_Reload(uint32_t ReloadType) +{ + HAL_LTDC_Reload (&hLtdcHandler, ReloadType); +} + +/** + * @brief Sets the LCD text color. + * @param Color: Text color code ARGB(8-8-8-8) + * @retval None + */ +void BSP_LCD_SetTextColor(uint32_t Color) +{ + DrawProp[ActiveLayer].TextColor = Color; +} + +/** + * @brief Gets the LCD text color. + * @retval Used text color. + */ +uint32_t BSP_LCD_GetTextColor(void) +{ + return DrawProp[ActiveLayer].TextColor; +} + +/** + * @brief Sets the LCD background color. + * @param Color: Layer background color code ARGB(8-8-8-8) + * @retval None + */ +void BSP_LCD_SetBackColor(uint32_t Color) +{ + DrawProp[ActiveLayer].BackColor = Color; +} + +/** + * @brief Gets the LCD background color. + * @retval Used background colour + */ +uint32_t BSP_LCD_GetBackColor(void) +{ + return DrawProp[ActiveLayer].BackColor; +} + +/** + * @brief Sets the LCD text font. + * @param fonts: Layer font to be used + * @retval None + */ +void BSP_LCD_SetFont(sFONT *fonts) +{ + DrawProp[ActiveLayer].pFont = fonts; +} + +/** + * @brief Gets the LCD text font. + * @retval Used layer font + */ +sFONT *BSP_LCD_GetFont(void) +{ + return DrawProp[ActiveLayer].pFont; +} + +/** + * @brief Reads an LCD pixel. + * @param Xpos: X position + * @param Ypos: Y position + * @retval RGB pixel color + */ +uint32_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos) +{ + uint32_t ret = 0; + + if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint32_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + else if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB888) + { + /* Read data value from SDRAM memory */ + ret = (*(__IO uint32_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))) & 0x00FFFFFF); + } + else if((hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \ + (hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \ + (hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_AL88)) + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint16_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + else + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint8_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + + return ret; +} + +/** + * @brief Clears the hole LCD. + * @param Color: Color of the background + * @retval None + */ +void BSP_LCD_Clear(uint32_t Color) +{ + /* Clear the LCD */ + LL_FillBuffer(ActiveLayer, (uint32_t *)(hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress), BSP_LCD_GetXSize(), BSP_LCD_GetYSize(), 0, Color); +} + +/** + * @brief Clears the selected line. + * @param Line: Line to be cleared + * @retval None + */ +void BSP_LCD_ClearStringLine(uint32_t Line) +{ + uint32_t color_backup = DrawProp[ActiveLayer].TextColor; + DrawProp[ActiveLayer].TextColor = DrawProp[ActiveLayer].BackColor; + + /* Draw rectangle with background color */ + BSP_LCD_FillRect(0, (Line * DrawProp[ActiveLayer].pFont->Height), BSP_LCD_GetXSize(), DrawProp[ActiveLayer].pFont->Height); + + DrawProp[ActiveLayer].TextColor = color_backup; + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Displays one character. + * @param Xpos: Start column address + * @param Ypos: Line where to display the character shape. + * @param Ascii: Character ascii code + * This parameter must be a number between Min_Data = 0x20 and Max_Data = 0x7E + * @retval None + */ +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii) +{ + DrawChar(Xpos, Ypos, &DrawProp[ActiveLayer].pFont->table[(Ascii-' ') *\ + DrawProp[ActiveLayer].pFont->Height * ((DrawProp[ActiveLayer].pFont->Width + 7) / 8)]); +} + +/** + * @brief Displays characters on the LCD. + * @param Xpos: X position (in pixel) + * @param Ypos: Y position (in pixel) + * @param Text: Pointer to string to display on LCD + * @param Mode: Display mode + * This parameter can be one of the following values: + * @arg CENTER_MODE + * @arg RIGHT_MODE + * @arg LEFT_MODE + * @retval None + */ +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode) +{ + uint16_t ref_column = 1, i = 0; + uint32_t size = 0, xsize = 0; + uint8_t *ptr = Text; + + /* Get the text size */ + while (*ptr++) size ++ ; + + /* Characters number per line */ + xsize = (BSP_LCD_GetXSize()/DrawProp[ActiveLayer].pFont->Width); + + switch (Mode) + { + case CENTER_MODE: + { + ref_column = Xpos + ((xsize - size)* DrawProp[ActiveLayer].pFont->Width) / 2; + break; + } + case LEFT_MODE: + { + ref_column = Xpos; + break; + } + case RIGHT_MODE: + { + ref_column = - Xpos + ((xsize - size)*DrawProp[ActiveLayer].pFont->Width); + break; + } + default: + { + ref_column = Xpos; + break; + } + } + + /* Check that the Start column is located in the screen */ + if ((ref_column < 1) || (ref_column >= 0x8000)) + { + ref_column = 1; + } + + /* Send the string character by character on LCD */ + while ((*Text != 0) & (((BSP_LCD_GetXSize() - (i*DrawProp[ActiveLayer].pFont->Width)) & 0xFFFF) >= DrawProp[ActiveLayer].pFont->Width)) + { + /* Display one character on LCD */ + BSP_LCD_DisplayChar(ref_column, Ypos, *Text); + /* Decrement the column position by 16 */ + ref_column += DrawProp[ActiveLayer].pFont->Width; + /* Point on the next character */ + Text++; + i++; + } +} + +/** + * @brief Displays a maximum of 60 characters on the LCD. + * @param Line: Line where to display the character shape + * @param ptr: Pointer to string to display on LCD + * @retval None + */ +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr) +{ + BSP_LCD_DisplayStringAt(0, LINE(Line), ptr, LEFT_MODE); +} + +/** + * @brief Draws an horizontal line. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + * @retval None + */ +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t Xaddress = 0; + + /* Get the line address */ + if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) + { /* RGB565 format */ + Xaddress = (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress) + 2*(BSP_LCD_GetXSize()*Ypos + Xpos); + } + else + { /* ARGB8888 format */ + Xaddress = (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + } + + /* Write line */ + LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, Length, 1, 0, DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws a vertical line. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + * @retval None + */ +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t Xaddress = 0; + + /* Get the line address */ + if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) + { /* RGB565 format */ + Xaddress = (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress) + 2*(BSP_LCD_GetXSize()*Ypos + Xpos); + } + else + { /* ARGB8888 format */ + Xaddress = (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + } + + /* Write line */ + LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, 1, Length, (BSP_LCD_GetXSize() - 1), DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws an uni-line (between two points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @retval None + */ +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, num_add = 0, num_pixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + num_add = deltay; + num_pixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + num_add = deltax; + num_pixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= num_pixels; curpixel++) + { + BSP_LCD_DrawPixel(x, y, DrawProp[ActiveLayer].TextColor); /* Draw the current pixel */ + num += num_add; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Draws a rectangle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + * @retval None + */ +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Draw horizontal lines */ + BSP_LCD_DrawHLine(Xpos, Ypos, Width); + BSP_LCD_DrawHLine(Xpos, (Ypos+ Height), Width); + + /* Draw vertical lines */ + BSP_LCD_DrawVLine(Xpos, Ypos, Height); + BSP_LCD_DrawVLine((Xpos + Width), Ypos, Height); +} + +/** + * @brief Draws a circle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + * @retval None + */ +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t decision; /* Decision Variable */ + uint32_t current_x; /* Current X Value */ + uint32_t current_y; /* Current Y Value */ + + decision = 3 - (Radius << 1); + current_x = 0; + current_y = Radius; + + while (current_x <= current_y) + { + BSP_LCD_DrawPixel((Xpos + current_x), (Ypos - current_y), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - current_x), (Ypos - current_y), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + current_y), (Ypos - current_x), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - current_y), (Ypos - current_x), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + current_x), (Ypos + current_y), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - current_x), (Ypos + current_y), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + current_y), (Ypos + current_x), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - current_y), (Ypos + current_x), DrawProp[ActiveLayer].TextColor); + + if (decision < 0) + { + decision += (current_x << 2) + 6; + } + else + { + decision += ((current_x - current_y) << 2) + 10; + current_y--; + } + current_x++; + } +} + +/** + * @brief Draws an poly-line (between many points). + * @param Points: Pointer to the points array + * @param PointCount: Number of points + * @retval None + */ +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t x = 0, y = 0; + + if(PointCount < 2) + { + return; + } + + BSP_LCD_DrawLine(Points->X, Points->Y, (Points+PointCount-1)->X, (Points+PointCount-1)->Y); + + while(--PointCount) + { + x = Points->X; + y = Points->Y; + Points++; + BSP_LCD_DrawLine(x, y, Points->X, Points->Y); + } +} + +/** + * @brief Draws an ellipse on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + * @retval None + */ +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float k = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + k = (float)(rad2/rad1); + + do { + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/k)), (Ypos+y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/k)), (Ypos+y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/k)), (Ypos-y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/k)), (Ypos-y), DrawProp[ActiveLayer].TextColor); + + e2 = err; + if (e2 <= x) { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Draws a pixel on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param RGB_Code: Pixel color in ARGB mode (8-8-8-8) + * @retval None + */ +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t RGB_Code) +{ + /* Write data value to all SDRAM memory */ + if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) + { /* RGB565 format */ + *(__IO uint16_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))) = (uint16_t)RGB_Code; + } + else + { /* ARGB8888 format */ + *(__IO uint32_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))) = RGB_Code; + } +} + +/** + * @brief Draws a bitmap picture loaded in the internal Flash in ARGB888 format (32 bits per pixel). + * @param Xpos: Bmp X position in the LCD + * @param Ypos: Bmp Y position in the LCD + * @param pbmp: Pointer to Bmp picture address in the internal Flash + * @retval None + */ +void BSP_LCD_DrawBitmap(uint32_t Xpos, uint32_t Ypos, uint8_t *pbmp) +{ + uint32_t index = 0, width = 0, height = 0, bit_pixel = 0; + uint32_t address; + uint32_t input_color_mode = 0; + + /* Get bitmap data address offset */ + index = pbmp[10] + (pbmp[11] << 8) + (pbmp[12] << 16) + (pbmp[13] << 24); + + /* Read bitmap width */ + width = pbmp[18] + (pbmp[19] << 8) + (pbmp[20] << 16) + (pbmp[21] << 24); + + /* Read bitmap height */ + height = pbmp[22] + (pbmp[23] << 8) + (pbmp[24] << 16) + (pbmp[25] << 24); + + /* Read bit/pixel */ + bit_pixel = pbmp[28] + (pbmp[29] << 8); + + /* Set the address */ + address = hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (((BSP_LCD_GetXSize()*Ypos) + Xpos)*(4)); + + /* Get the layer pixel format */ + if ((bit_pixel/8) == 4) + { + input_color_mode = CM_ARGB8888; + } + else if ((bit_pixel/8) == 2) + { + input_color_mode = CM_RGB565; + } + else + { + input_color_mode = CM_RGB888; + } + + /* Bypass the bitmap header */ + pbmp += (index + (width * (height - 1) * (bit_pixel/8))); + + /* Convert picture to ARGB8888 pixel format */ + for(index=0; index < height; index++) + { + /* Pixel format conversion */ + LL_ConvertLineToARGB8888((uint32_t *)pbmp, (uint32_t *)address, width, input_color_mode); + + /* Increment the source and destination buffers */ + address+= (BSP_LCD_GetXSize()*4); + pbmp -= width*(bit_pixel/8); + } +} + +/** + * @brief Draws a full rectangle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + * @retval None + */ +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + uint32_t x_address = 0; + + /* Set the text color */ + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + + /* Get the rectangle start address */ + if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) + { /* RGB565 format */ + x_address = (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress) + 2*(BSP_LCD_GetXSize()*Ypos + Xpos); + } + else + { /* ARGB8888 format */ + x_address = (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + } + /* Fill the rectangle */ + LL_FillBuffer(ActiveLayer, (uint32_t *)x_address, Width, Height, (BSP_LCD_GetXSize() - Width), DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws a full circle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + * @retval None + */ +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t decision; /* Decision Variable */ + uint32_t current_x; /* Current X Value */ + uint32_t current_y; /* Current Y Value */ + + decision = 3 - (Radius << 1); + + current_x = 0; + current_y = Radius; + + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + + while (current_x <= current_y) + { + if(current_y > 0) + { + BSP_LCD_DrawHLine(Xpos - current_y, Ypos + current_x, 2*current_y); + BSP_LCD_DrawHLine(Xpos - current_y, Ypos - current_x, 2*current_y); + } + + if(current_x > 0) + { + BSP_LCD_DrawHLine(Xpos - current_x, Ypos - current_y, 2*current_x); + BSP_LCD_DrawHLine(Xpos - current_x, Ypos + current_y, 2*current_x); + } + if (decision < 0) + { + decision += (current_x << 2) + 6; + } + else + { + decision += ((current_x - current_y) << 2) + 10; + current_y--; + } + current_x++; + } + + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawCircle(Xpos, Ypos, Radius); +} + +/** + * @brief Draws a full poly-line (between many points). + * @param Points: Pointer to the points array + * @param PointCount: Number of points + * @retval None + */ +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t X = 0, Y = 0, X2 = 0, Y2 = 0, X_center = 0, Y_center = 0, X_first = 0, Y_first = 0, pixelX = 0, pixelY = 0, counter = 0; + uint16_t image_left = 0, image_right = 0, image_top = 0, image_bottom = 0; + + image_left = image_right = Points->X; + image_top= image_bottom = Points->Y; + + for(counter = 1; counter < PointCount; counter++) + { + pixelX = POLY_X(counter); + if(pixelX < image_left) + { + image_left = pixelX; + } + if(pixelX > image_right) + { + image_right = pixelX; + } + + pixelY = POLY_Y(counter); + if(pixelY < image_top) + { + image_top = pixelY; + } + if(pixelY > image_bottom) + { + image_bottom = pixelY; + } + } + + if(PointCount < 2) + { + return; + } + + X_center = (image_left + image_right)/2; + Y_center = (image_bottom + image_top)/2; + + X_first = Points->X; + Y_first = Points->Y; + + while(--PointCount) + { + X = Points->X; + Y = Points->Y; + Points++; + X2 = Points->X; + Y2 = Points->Y; + + FillTriangle(X, X2, X_center, Y, Y2, Y_center); + FillTriangle(X, X_center, X2, Y, Y_center, Y2); + FillTriangle(X_center, X2, X, Y_center, Y2, Y); + } + + FillTriangle(X_first, X2, X_center, Y_first, Y2, Y_center); + FillTriangle(X_first, X_center, X2, Y_first, Y_center, Y2); + FillTriangle(X_center, X2, X_first, Y_center, Y2, Y_first); +} + +/** + * @brief Draws a full ellipse. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + * @retval None + */ +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float k = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + k = (float)(rad2/rad1); + + do + { + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/k)), (Ypos+y), (2*(uint16_t)(x/k) + 1)); + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/k)), (Ypos-y), (2*(uint16_t)(x/k) + 1)); + + e2 = err; + if (e2 <= x) + { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Enables the display. + * @retval None + */ +void BSP_LCD_DisplayOn(void) +{ + /* Display On */ + __HAL_LTDC_ENABLE(&hLtdcHandler); + HAL_GPIO_WritePin(LCD_DISP_GPIO_PORT, LCD_DISP_PIN, GPIO_PIN_SET); /* Assert LCD_DISP pin */ + HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_PORT, LCD_BL_CTRL_PIN, GPIO_PIN_SET); /* Assert LCD_BL_CTRL pin */ +} + +/** + * @brief Disables the display. + * @retval None + */ +void BSP_LCD_DisplayOff(void) +{ + /* Display Off */ + __HAL_LTDC_DISABLE(&hLtdcHandler); + HAL_GPIO_WritePin(LCD_DISP_GPIO_PORT, LCD_DISP_PIN, GPIO_PIN_RESET); /* De-assert LCD_DISP pin */ + HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_PORT, LCD_BL_CTRL_PIN, GPIO_PIN_RESET);/* De-assert LCD_BL_CTRL pin */ +} + +/** + * @brief Initializes the LTDC MSP. + * @param hltdc: LTDC handle + * @param Params + * @retval None + */ +__weak void BSP_LCD_MspInit(LTDC_HandleTypeDef *hltdc, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable the LTDC and DMA2D clocks */ + __HAL_RCC_LTDC_CLK_ENABLE(); + __HAL_RCC_DMA2D_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + __HAL_RCC_GPIOJ_CLK_ENABLE(); + __HAL_RCC_GPIOK_CLK_ENABLE(); + LCD_DISP_GPIO_CLK_ENABLE(); + LCD_BL_CTRL_GPIO_CLK_ENABLE(); + + /*** LTDC Pins configuration ***/ + /* GPIOE configuration */ + gpio_init_structure.Pin = GPIO_PIN_4; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = GPIO_AF14_LTDC; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_12; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = GPIO_AF9_LTDC; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + /* GPIOI LTDC alternate configuration */ + gpio_init_structure.Pin = GPIO_PIN_9 | GPIO_PIN_10 | \ + GPIO_PIN_14 | GPIO_PIN_15; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = GPIO_AF14_LTDC; + HAL_GPIO_Init(GPIOI, &gpio_init_structure); + + /* GPIOJ configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \ + GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | \ + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | \ + GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = GPIO_AF14_LTDC; + HAL_GPIO_Init(GPIOJ, &gpio_init_structure); + + /* GPIOK configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | \ + GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = GPIO_AF14_LTDC; + HAL_GPIO_Init(GPIOK, &gpio_init_structure); + + /* LCD_DISP GPIO configuration */ + gpio_init_structure.Pin = LCD_DISP_PIN; /* LCD_DISP pin has to be manually controlled */ + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + HAL_GPIO_Init(LCD_DISP_GPIO_PORT, &gpio_init_structure); + + /* LCD_BL_CTRL GPIO configuration */ + gpio_init_structure.Pin = LCD_BL_CTRL_PIN; /* LCD_BL_CTRL pin has to be manually controlled */ + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + HAL_GPIO_Init(LCD_BL_CTRL_GPIO_PORT, &gpio_init_structure); +} + +/** + * @brief DeInitializes BSP_LCD MSP. + * @param hltdc: LTDC handle + * @param Params + * @retval None + */ +__weak void BSP_LCD_MspDeInit(LTDC_HandleTypeDef *hltdc, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Disable LTDC block */ + __HAL_LTDC_DISABLE(hltdc); + + /* LTDC Pins deactivation */ + + /* GPIOE deactivation */ + gpio_init_structure.Pin = GPIO_PIN_4; + HAL_GPIO_DeInit(GPIOE, gpio_init_structure.Pin); + + /* GPIOG deactivation */ + gpio_init_structure.Pin = GPIO_PIN_12; + HAL_GPIO_DeInit(GPIOG, gpio_init_structure.Pin); + + /* GPIOI deactivation */ + gpio_init_structure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_12 | \ + GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_DeInit(GPIOI, gpio_init_structure.Pin); + + /* GPIOJ deactivation */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \ + GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | \ + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | \ + GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_DeInit(GPIOJ, gpio_init_structure.Pin); + + /* GPIOK deactivation */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | \ + GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; + HAL_GPIO_DeInit(GPIOK, gpio_init_structure.Pin); + + /* Disable LTDC clock */ + __HAL_RCC_LTDC_CLK_DISABLE(); + + /* GPIO pins clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Clock Config. + * @param hltdc: LTDC handle + * @param Params + * @note This API is called by BSP_LCD_Init() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_LCD_ClockConfig(LTDC_HandleTypeDef *hltdc, void *Params) +{ + static RCC_PeriphCLKInitTypeDef periph_clk_init_struct; + + /* RK043FN48H LCD clock configuration */ + /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */ + /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 Mhz */ + /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/5 = 38.4 Mhz */ + /* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_4 = 38.4/4 = 9.6Mhz */ + periph_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; + periph_clk_init_struct.PLLSAI.PLLSAIN = 192; + periph_clk_init_struct.PLLSAI.PLLSAIR = RK043FN48H_FREQUENCY_DIVIDER; + periph_clk_init_struct.PLLSAIDivR = RCC_PLLSAIDIVR_4; + HAL_RCCEx_PeriphCLKConfig(&periph_clk_init_struct); +} + + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Draws a character on LCD. + * @param Xpos: Line where to display the character shape + * @param Ypos: Start column address + * @param c: Pointer to the character data + * @retval None + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c) +{ + uint32_t i = 0, j = 0; + uint16_t height, width; + uint8_t offset; + uint8_t *pchar; + uint32_t line; + + height = DrawProp[ActiveLayer].pFont->Height; + width = DrawProp[ActiveLayer].pFont->Width; + + offset = 8 *((width + 7)/8) - width ; + + for(i = 0; i < height; i++) + { + pchar = ((uint8_t *)c + (width + 7)/8 * i); + + switch(((width + 7)/8)) + { + + case 1: + line = pchar[0]; + break; + + case 2: + line = (pchar[0]<< 8) | pchar[1]; + break; + + case 3: + default: + line = (pchar[0]<< 16) | (pchar[1]<< 8) | pchar[2]; + break; + } + + for (j = 0; j < width; j++) + { + if(line & (1 << (width- j + offset- 1))) + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp[ActiveLayer].TextColor); + } + else + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp[ActiveLayer].BackColor); + } + } + Ypos++; + } +} + +/** + * @brief Fills a triangle (between 3 points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @param x3: Point 3 X position + * @param y3: Point 3 Y position + * @retval None + */ +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, num_add = 0, num_pixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + num_add = deltay; + num_pixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + num_add = deltax; + num_pixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= num_pixels; curpixel++) + { + BSP_LCD_DrawLine(x, y, x3, y3); + + num += num_add; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Fills a buffer. + * @param LayerIndex: Layer index + * @param pDst: Pointer to destination buffer + * @param xSize: Buffer width + * @param ySize: Buffer height + * @param OffLine: Offset + * @param ColorIndex: Color index + * @retval None + */ +static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex) +{ + /* Register to memory mode with ARGB8888 as color Mode */ + hDma2dHandler.Init.Mode = DMA2D_R2M; + if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) + { /* RGB565 format */ + hDma2dHandler.Init.ColorMode = DMA2D_RGB565; + } + else + { /* ARGB8888 format */ + hDma2dHandler.Init.ColorMode = DMA2D_ARGB8888; + } + hDma2dHandler.Init.OutputOffset = OffLine; + + hDma2dHandler.Instance = DMA2D; + + /* DMA2D Initialization */ + if(HAL_DMA2D_Init(&hDma2dHandler) == HAL_OK) + { + if(HAL_DMA2D_ConfigLayer(&hDma2dHandler, LayerIndex) == HAL_OK) + { + if (HAL_DMA2D_Start(&hDma2dHandler, ColorIndex, (uint32_t)pDst, xSize, ySize) == HAL_OK) + { + /* Polling For DMA transfer */ + HAL_DMA2D_PollForTransfer(&hDma2dHandler, 10); + } + } + } +} + +/** + * @brief Converts a line to an ARGB8888 pixel format. + * @param pSrc: Pointer to source buffer + * @param pDst: Output color + * @param xSize: Buffer width + * @param ColorMode: Input color mode + * @retval None + */ +static void LL_ConvertLineToARGB8888(void *pSrc, void *pDst, uint32_t xSize, uint32_t ColorMode) +{ + /* Configure the DMA2D Mode, Color Mode and output offset */ + hDma2dHandler.Init.Mode = DMA2D_M2M_PFC; + hDma2dHandler.Init.ColorMode = DMA2D_ARGB8888; + hDma2dHandler.Init.OutputOffset = 0; + + /* Foreground Configuration */ + hDma2dHandler.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; + hDma2dHandler.LayerCfg[1].InputAlpha = 0xFF; + hDma2dHandler.LayerCfg[1].InputColorMode = ColorMode; + hDma2dHandler.LayerCfg[1].InputOffset = 0; + + hDma2dHandler.Instance = DMA2D; + + /* DMA2D Initialization */ + if(HAL_DMA2D_Init(&hDma2dHandler) == HAL_OK) + { + if(HAL_DMA2D_ConfigLayer(&hDma2dHandler, 1) == HAL_OK) + { + if (HAL_DMA2D_Start(&hDma2dHandler, (uint32_t)pSrc, (uint32_t)pDst, xSize, 1) == HAL_OK) + { + /* Polling For DMA transfer */ + HAL_DMA2D_PollForTransfer(&hDma2dHandler, 10); + } + } + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_lcd.h b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_lcd.h new file mode 100644 index 00000000..160e7b10 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_lcd.h @@ -0,0 +1,267 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_lcd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32746g_discovery_lcd.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32746G_DISCOVERY_LCD_H +#define __STM32746G_DISCOVERY_LCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include LCD component Driver */ +/* LCD RK043FN48H-CT672B 4,3" 480x272 pixels */ +#include "../Components/rk043fn48h/rk043fn48h.h" + +/* Include SDRAM Driver */ +#include "stm32746g_discovery_sdram.h" + +#include "stm32746g_discovery.h" +#include "../../../Utilities/Fonts/fonts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY_LCD + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_LCD_Exported_Types STM32746G_DISCOVERY_LCD Exported Types + * @{ + */ +typedef struct +{ + uint32_t TextColor; + uint32_t BackColor; + sFONT *pFont; +}LCD_DrawPropTypeDef; + +typedef struct +{ + int16_t X; + int16_t Y; +}Point, * pPoint; + +/** + * @brief Line mode structures definition + */ +typedef enum +{ + CENTER_MODE = 0x01, /* Center mode */ + RIGHT_MODE = 0x02, /* Right mode */ + LEFT_MODE = 0x03 /* Left mode */ +}Text_AlignModeTypdef; + +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_LCD_Exported_Constants STM32746G_DISCOVERY_LCD Exported Constants + * @{ + */ +#define MAX_LAYER_NUMBER ((uint32_t)2) + +#define LCD_LayerCfgTypeDef LTDC_LayerCfgTypeDef + +#define LTDC_ACTIVE_LAYER ((uint32_t)1) /* Layer 1 */ +/** + * @brief LCD status structure definition + */ +#define LCD_OK ((uint8_t)0x00) +#define LCD_ERROR ((uint8_t)0x01) +#define LCD_TIMEOUT ((uint8_t)0x02) + +/** + * @brief LCD FB_StartAddress + */ +#define LCD_FB_START_ADDRESS ((uint32_t)0xC0000000) + +/** + * @brief LCD color + */ +#define LCD_COLOR_BLUE ((uint32_t)0xFF0000FF) +#define LCD_COLOR_GREEN ((uint32_t)0xFF00FF00) +#define LCD_COLOR_RED ((uint32_t)0xFFFF0000) +#define LCD_COLOR_CYAN ((uint32_t)0xFF00FFFF) +#define LCD_COLOR_MAGENTA ((uint32_t)0xFFFF00FF) +#define LCD_COLOR_YELLOW ((uint32_t)0xFFFFFF00) +#define LCD_COLOR_LIGHTBLUE ((uint32_t)0xFF8080FF) +#define LCD_COLOR_LIGHTGREEN ((uint32_t)0xFF80FF80) +#define LCD_COLOR_LIGHTRED ((uint32_t)0xFFFF8080) +#define LCD_COLOR_LIGHTCYAN ((uint32_t)0xFF80FFFF) +#define LCD_COLOR_LIGHTMAGENTA ((uint32_t)0xFFFF80FF) +#define LCD_COLOR_LIGHTYELLOW ((uint32_t)0xFFFFFF80) +#define LCD_COLOR_DARKBLUE ((uint32_t)0xFF000080) +#define LCD_COLOR_DARKGREEN ((uint32_t)0xFF008000) +#define LCD_COLOR_DARKRED ((uint32_t)0xFF800000) +#define LCD_COLOR_DARKCYAN ((uint32_t)0xFF008080) +#define LCD_COLOR_DARKMAGENTA ((uint32_t)0xFF800080) +#define LCD_COLOR_DARKYELLOW ((uint32_t)0xFF808000) +#define LCD_COLOR_WHITE ((uint32_t)0xFFFFFFFF) +#define LCD_COLOR_LIGHTGRAY ((uint32_t)0xFFD3D3D3) +#define LCD_COLOR_GRAY ((uint32_t)0xFF808080) +#define LCD_COLOR_DARKGRAY ((uint32_t)0xFF404040) +#define LCD_COLOR_BLACK ((uint32_t)0xFF000000) +#define LCD_COLOR_BROWN ((uint32_t)0xFFA52A2A) +#define LCD_COLOR_ORANGE ((uint32_t)0xFFFFA500) +#define LCD_COLOR_TRANSPARENT ((uint32_t)0xFF000000) + +/** + * @brief LCD default font + */ +#define LCD_DEFAULT_FONT Font24 + +/** + * @brief LCD Reload Types + */ +#define LCD_RELOAD_IMMEDIATE ((uint32_t)LTDC_SRCR_IMR) +#define LCD_RELOAD_VERTICAL_BLANKING ((uint32_t)LTDC_SRCR_VBR) + + +/** + * @brief LCD special pins + */ +/* Display enable pin */ +#define LCD_DISP_PIN GPIO_PIN_12 +#define LCD_DISP_GPIO_PORT GPIOI +#define LCD_DISP_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define LCD_DISP_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() + +/* Backlight control pin */ +#define LCD_BL_CTRL_PIN GPIO_PIN_3 +#define LCD_BL_CTRL_GPIO_PORT GPIOK +#define LCD_BL_CTRL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOK_CLK_ENABLE() +#define LCD_BL_CTRL_GPIO_CLK_DISABLE() __HAL_RCC_GPIOK_CLK_DISABLE() + +/** + * @} + */ + +/** @addtogroup STM32746G_DISCOVERY_LCD_Exported_Functions + * @{ + */ +uint8_t BSP_LCD_Init(void); +uint8_t BSP_LCD_DeInit(void); +uint32_t BSP_LCD_GetXSize(void); +uint32_t BSP_LCD_GetYSize(void); +void BSP_LCD_SetXSize(uint32_t imageWidthPixels); +void BSP_LCD_SetYSize(uint32_t imageHeightPixels); + +/* Functions using the LTDC controller */ +void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FrameBuffer); +void BSP_LCD_LayerRgb565Init(uint16_t LayerIndex, uint32_t FB_Address); +void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency); +void BSP_LCD_SetTransparency_NoReload(uint32_t LayerIndex, uint8_t Transparency); +void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address); +void BSP_LCD_SetLayerAddress_NoReload(uint32_t LayerIndex, uint32_t Address); +void BSP_LCD_SetColorKeying(uint32_t LayerIndex, uint32_t RGBValue); +void BSP_LCD_SetColorKeying_NoReload(uint32_t LayerIndex, uint32_t RGBValue); +void BSP_LCD_ResetColorKeying(uint32_t LayerIndex); +void BSP_LCD_ResetColorKeying_NoReload(uint32_t LayerIndex); +void BSP_LCD_SetLayerWindow(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_SetLayerWindow_NoReload(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_SelectLayer(uint32_t LayerIndex); +void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState State); +void BSP_LCD_SetLayerVisible_NoReload(uint32_t LayerIndex, FunctionalState State); +void BSP_LCD_Reload(uint32_t ReloadType); + +void BSP_LCD_SetTextColor(uint32_t Color); +uint32_t BSP_LCD_GetTextColor(void); +void BSP_LCD_SetBackColor(uint32_t Color); +uint32_t BSP_LCD_GetBackColor(void); +void BSP_LCD_SetFont(sFONT *fonts); +sFONT *BSP_LCD_GetFont(void); + +uint32_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos); +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t pixel); +void BSP_LCD_Clear(uint32_t Color); +void BSP_LCD_ClearStringLine(uint32_t Line); +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr); +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode); +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii); + +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius); +void BSP_LCD_DrawBitmap(uint32_t Xpos, uint32_t Ypos, uint8_t *pbmp); + +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius); + +void BSP_LCD_DisplayOff(void); +void BSP_LCD_DisplayOn(void); + +/* These functions can be modified in case the current settings + need to be changed for specific application needs */ +void BSP_LCD_MspInit(LTDC_HandleTypeDef *hltdc, void *Params); +void BSP_LCD_MspDeInit(LTDC_HandleTypeDef *hltdc, void *Params); +void BSP_LCD_ClockConfig(LTDC_HandleTypeDef *hltdc, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32746G_DISCOVERY_LCD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_qspi.c b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_qspi.c new file mode 100644 index 00000000..fec6ab59 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_qspi.c @@ -0,0 +1,798 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_qspi.c + * @author MCD Application Team + * @brief This file includes a standard driver for the N25Q128A QSPI + * memory mounted on STM32746G-Discovery board. + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + (#) This driver is used to drive the N25Q128A QSPI external + memory mounted on STM32746G-Discovery board. + + (#) This driver need a specific component driver (N25Q128A) to be included with. + + (#) Initialization steps: + (++) Initialize the QPSI external memory using the BSP_QSPI_Init() function. This + function includes the MSP layer hardware resources initialization and the + QSPI interface with the external memory. + + (#) QSPI memory operations + (++) QSPI memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_QSPI_Read()/BSP_QSPI_Write(). + (++) The function BSP_QSPI_GetInfo() returns the configuration of the QSPI memory. + (see the QSPI memory data sheet) + (++) Perform erase block operation using the function BSP_QSPI_Erase_Block() and by + specifying the block address. You can perform an erase operation of the whole + chip by calling the function BSP_QSPI_Erase_Chip(). + (++) The function BSP_QSPI_GetStatus() returns the current status of the QSPI memory. + (see the QSPI memory data sheet) + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_qspi.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- n25q128a.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32746g_discovery_qspi.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_QSPI STM32746G-Discovery QSPI + * @{ + */ + + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup STM32746G_DISCOVERY_QSPI_Private_Variables STM32746G_DISCOVERY QSPI Private Variables + * @{ + */ +QSPI_HandleTypeDef QSPIHandle; + +/** + * @} + */ + + + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup STM32746G_DISCOVERY_QSPI_Private_Functions STM32746G_DISCOVERY QSPI Private Functions + * @{ + */ +static uint8_t QSPI_ResetMemory (QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_DummyCyclesCfg (QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_WriteEnable (QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_AutoPollingMemReady (QSPI_HandleTypeDef *hqspi, uint32_t Timeout); + +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_QSPI_Exported_Functions STM32746G_DISCOVERY QSPI Exported Functions + * @{ + */ + +/** + * @brief Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Init(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level initialization */ + BSP_QSPI_MspInit(&QSPIHandle, NULL); + + /* QSPI initialization */ + QSPIHandle.Init.ClockPrescaler = 1; /* QSPI freq = 216 MHz/(1+1) = 108 Mhz */ + QSPIHandle.Init.FifoThreshold = 4; + QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; + QSPIHandle.Init.FlashSize = POSITION_VAL(N25Q128A_FLASH_SIZE) - 1; + QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE; /* Min 50ns for nonRead */ + QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; + QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1; + QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE; + + if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* QSPI memory reset */ + if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Configuration of the dummy cycles on QSPI memory side */ + if (QSPI_DummyCyclesCfg(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + return QSPI_OK; +} + +/** + * @brief De-Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_DeInit(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level De-initialization */ + BSP_QSPI_MspDeInit(&QSPIHandle, NULL); + + return QSPI_OK; +} + +/** + * @brief Reads an amount of data from the QSPI memory. + * @param pData: Pointer to data to be read + * @param ReadAddr: Read start address + * @param Size: Size of data to read + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the read command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = QUAD_INOUT_FAST_READ_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.Address = ReadAddr; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = N25Q128A_DUMMY_CYCLES_READ_QUAD; + s_command.NbData = Size; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Set S# timing for Read command */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_3_CYCLE); + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Restore S# timing for nonRead commands */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_6_CYCLE); + + return QSPI_OK; +} + +/** + * @brief Writes an amount of data to the QSPI memory. + * @param pData: Pointer to data to be written + * @param WriteAddr: Write start address + * @param Size: Size of data to write + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + uint32_t end_addr, current_size, current_addr; + + /* Calculation of the size between the write address and the end of the page */ + current_size = N25Q128A_PAGE_SIZE - (WriteAddr % N25Q128A_PAGE_SIZE); + + /* Check if the size of the data is less than the remaining place in the page */ + if (current_size > Size) + { + current_size = Size; + } + + /* Initialize the adress variables */ + current_addr = WriteAddr; + end_addr = WriteAddr + Size; + + /* Initialize the program command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = EXT_QUAD_IN_FAST_PROG_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Perform the write page by page */ + do + { + s_command.Address = current_addr; + s_command.NbData = current_size; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of program */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update the address and size variables for next page programming */ + current_addr += current_size; + pData += current_size; + current_size = ((current_addr + N25Q128A_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : N25Q128A_PAGE_SIZE; + } while (current_addr < end_addr); + + return QSPI_OK; +} + +/** + * @brief Erases the specified block of the QSPI memory. + * @param BlockAddress: Block address to erase + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = SUBSECTOR_ERASE_CMD; + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.Address = BlockAddress; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, N25Q128A_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Erases the entire QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Chip(void) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = BULK_ERASE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, N25Q128A_BULK_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Reads current status of the QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetStatus(void) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg; + + /* Initialize the read flag status register command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_FLAG_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Check the value of the register */ + if ((reg & (N25Q128A_FSR_PRERR | N25Q128A_FSR_VPPERR | N25Q128A_FSR_PGERR | N25Q128A_FSR_ERERR)) != 0) + { + return QSPI_ERROR; + } + else if ((reg & (N25Q128A_FSR_PGSUS | N25Q128A_FSR_ERSUS)) != 0) + { + return QSPI_SUSPENDED; + } + else if ((reg & N25Q128A_FSR_READY) != 0) + { + return QSPI_OK; + } + else + { + return QSPI_BUSY; + } +} + +/** + * @brief Return the configuration of the QSPI memory. + * @param pInfo: pointer on the configuration structure + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetInfo(QSPI_Info* pInfo) +{ + /* Configure the structure with the memory configuration */ + pInfo->FlashSize = N25Q128A_FLASH_SIZE; + pInfo->EraseSectorSize = N25Q128A_SUBSECTOR_SIZE; + pInfo->EraseSectorsNumber = (N25Q128A_FLASH_SIZE/N25Q128A_SUBSECTOR_SIZE); + pInfo->ProgPageSize = N25Q128A_PAGE_SIZE; + pInfo->ProgPagesNumber = (N25Q128A_FLASH_SIZE/N25Q128A_PAGE_SIZE); + + return QSPI_OK; +} + +/** + * @brief Configure the QSPI in memory-mapped mode + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_EnableMemoryMappedMode(void) +{ + QSPI_CommandTypeDef s_command; + QSPI_MemoryMappedTypeDef s_mem_mapped_cfg; + + /* Configure the command for the read instruction */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = QUAD_INOUT_FAST_READ_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = N25Q128A_DUMMY_CYCLES_READ_QUAD; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the memory mapped mode */ + s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; + s_mem_mapped_cfg.TimeOutPeriod = 0; + + if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @} + */ + +/** @addtogroup STM32746G_DISCOVERY_QSPI_Private_Functions + * @{ + */ + +/** + * @brief QSPI MSP Initialization + * This function configures the hardware resources used in this example: + * - Peripheral's clock enable + * - Peripheral's GPIO Configuration + * - NVIC configuration for QSPI interrupt + * @retval None + */ +__weak void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /*##-1- Enable peripherals and GPIO Clocks #################################*/ + /* Enable the QuadSPI memory interface clock */ + QSPI_CLK_ENABLE(); + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + /* Enable GPIO clocks */ + QSPI_CS_GPIO_CLK_ENABLE(); + QSPI_CLK_GPIO_CLK_ENABLE(); + QSPI_D0_GPIO_CLK_ENABLE(); + QSPI_D1_GPIO_CLK_ENABLE(); + QSPI_D2_GPIO_CLK_ENABLE(); + QSPI_D3_GPIO_CLK_ENABLE(); + + /*##-2- Configure peripheral GPIO ##########################################*/ + /* QSPI CS GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CS_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF10_QUADSPI; + HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &gpio_init_structure); + + /* QSPI CLK GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CLK_PIN; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &gpio_init_structure); + + /* QSPI D0 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D0_PIN; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_D0_GPIO_PORT, &gpio_init_structure); + + /* QSPI D1 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D1_PIN; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_D1_GPIO_PORT, &gpio_init_structure); + + /* QSPI D2 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D2_PIN; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_D2_GPIO_PORT, &gpio_init_structure); + + /* QSPI D3 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D3_PIN; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_D3_GPIO_PORT, &gpio_init_structure); + + /*##-3- Configure the NVIC for QSPI #########################################*/ + /* NVIC configuration for QSPI interrupt */ + HAL_NVIC_SetPriority(QUADSPI_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(QUADSPI_IRQn); +} + +/** + * @brief QSPI MSP De-Initialization + * This function frees the hardware resources used in this example: + * - Disable the Peripheral's clock + * - Revert GPIO and NVIC configuration to their default state + * @retval None + */ +__weak void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + /*##-1- Disable the NVIC for QSPI ###########################################*/ + HAL_NVIC_DisableIRQ(QUADSPI_IRQn); + + /*##-2- Disable peripherals and GPIO Clocks ################################*/ + /* De-Configure QSPI pins */ + HAL_GPIO_DeInit(QSPI_CS_GPIO_PORT, QSPI_CS_PIN); + HAL_GPIO_DeInit(QSPI_CLK_GPIO_PORT, QSPI_CLK_PIN); + HAL_GPIO_DeInit(QSPI_D0_GPIO_PORT, QSPI_D0_PIN); + HAL_GPIO_DeInit(QSPI_D1_GPIO_PORT, QSPI_D1_PIN); + HAL_GPIO_DeInit(QSPI_D2_GPIO_PORT, QSPI_D2_PIN); + HAL_GPIO_DeInit(QSPI_D3_GPIO_PORT, QSPI_D3_PIN); + + /*##-3- Reset peripherals ##################################################*/ + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + + /* Disable the QuadSPI memory interface clock */ + QSPI_CLK_DISABLE(); +} + +/** + * @brief This function reset the QSPI memory. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the reset enable command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = RESET_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Send the reset memory command */ + s_command.Instruction = RESET_MEMORY_CMD; + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait the memory is ready */ + if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function configure the dummy cycles on memory side. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg; + + /* Initialize the read volatile configuration register command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_VOL_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations */ + if (QSPI_WriteEnable(hqspi) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update volatile configuration register (with new dummy cycles) */ + s_command.Instruction = WRITE_VOL_CFG_REG_CMD; + MODIFY_REG(reg, N25Q128A_VCR_NB_DUMMY, (N25Q128A_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(N25Q128A_VCR_NB_DUMMY))); + + /* Configure the write volatile configuration register command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function send a Write Enable and wait it is effective. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Enable write operations */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = WRITE_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for write enabling */ + s_config.Match = N25Q128A_SR_WREN; + s_config.Mask = N25Q128A_SR_WREN; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_1_LINE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function read the SR of the memory and wait the EOP. + * @param hqspi: QSPI handle + * @param Timeout + * @retval None + */ +static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Configure automatic polling mode to wait for memory ready */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + s_config.Match = 0; + s_config.Mask = N25Q128A_SR_WIP; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, Timeout) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_qspi.h b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_qspi.h new file mode 100644 index 00000000..ba8ce8bd --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_qspi.h @@ -0,0 +1,170 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_qspi.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32746g_discovery_qspi.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32746G_DISCOVERY_QSPI_H +#define __STM32746G_DISCOVERY_QSPI_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" +#include "../Components/n25q128a/n25q128a.h" + +/** @addtogroup STM32746G_DISCOVERY_QSPI + * @{ + */ + + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup STM32746G_DISCOVERY_QSPI_Exported_Constants STM32746G_DISCOVERY_QSPI Exported Constants + * @{ + */ +/* QSPI Error codes */ +#define QSPI_OK ((uint8_t)0x00) +#define QSPI_ERROR ((uint8_t)0x01) +#define QSPI_BUSY ((uint8_t)0x02) +#define QSPI_NOT_SUPPORTED ((uint8_t)0x04) +#define QSPI_SUSPENDED ((uint8_t)0x08) + + +/* Definition for QSPI clock resources */ +#define QSPI_CLK_ENABLE() __HAL_RCC_QSPI_CLK_ENABLE() +#define QSPI_CLK_DISABLE() __HAL_RCC_QSPI_CLK_DISABLE() +#define QSPI_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_CLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_D0_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() +#define QSPI_D1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() +#define QSPI_D2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() +#define QSPI_D3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() + +#define QSPI_FORCE_RESET() __HAL_RCC_QSPI_FORCE_RESET() +#define QSPI_RELEASE_RESET() __HAL_RCC_QSPI_RELEASE_RESET() + +/* Definition for QSPI Pins */ +#define QSPI_CS_PIN GPIO_PIN_6 +#define QSPI_CS_GPIO_PORT GPIOB +#define QSPI_CLK_PIN GPIO_PIN_2 +#define QSPI_CLK_GPIO_PORT GPIOB +#define QSPI_D0_PIN GPIO_PIN_11 +#define QSPI_D0_GPIO_PORT GPIOD +#define QSPI_D1_PIN GPIO_PIN_12 +#define QSPI_D1_GPIO_PORT GPIOD +#define QSPI_D2_PIN GPIO_PIN_2 +#define QSPI_D2_GPIO_PORT GPIOE +#define QSPI_D3_PIN GPIO_PIN_13 +#define QSPI_D3_GPIO_PORT GPIOD + +/* N25Q128A13EF840E Micron memory */ +/* Size of the flash */ +#define QSPI_FLASH_SIZE 23 /* Address bus width to access whole memory space */ +#define QSPI_PAGE_SIZE 256 + +/* This alias is added as the name of Memory mapped fucntion changed */ +#define BSP_QSPI_MemoryMappedMode BSP_QSPI_EnableMemoryMappedMode +/** + * @} + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup STM32746G_DISCOVERY_QSPI_Exported_Types STM32746G_DISCOVERY_QSPI Exported Types + * @{ + */ +/* QSPI Info */ +typedef struct { + uint32_t FlashSize; /*!< Size of the flash */ + uint32_t EraseSectorSize; /*!< Size of sectors for the erase operation */ + uint32_t EraseSectorsNumber; /*!< Number of sectors for the erase operation */ + uint32_t ProgPageSize; /*!< Size of pages for the program operation */ + uint32_t ProgPagesNumber; /*!< Number of pages for the program operation */ +} QSPI_Info; + +/** + * @} + */ + + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup STM32746G_DISCOVERY_QSPI_Exported_Functions + * @{ + */ +uint8_t BSP_QSPI_Init (void); +uint8_t BSP_QSPI_DeInit (void); +uint8_t BSP_QSPI_Read (uint8_t* pData, uint32_t ReadAddr, uint32_t Size); +uint8_t BSP_QSPI_Write (uint8_t* pData, uint32_t WriteAddr, uint32_t Size); +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress); +uint8_t BSP_QSPI_Erase_Chip (void); +uint8_t BSP_QSPI_GetStatus (void); +uint8_t BSP_QSPI_GetInfo (QSPI_Info* pInfo); +uint8_t BSP_QSPI_EnableMemoryMappedMode(void); + +/* These functions can be modified in case the current settings + need to be changed for specific application needs */ +void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params); +void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32746G_DISCOVERY_QSPI_H */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sd.c b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sd.c new file mode 100644 index 00000000..e5f686c0 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sd.c @@ -0,0 +1,606 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_sd.c + * @author MCD Application Team + * @brief This file includes the uSD card driver mounted on STM32746G-Discovery + * board. + @verbatim + 1. How To use this driver: + -------------------------- + - This driver is used to drive the micro SD external card mounted on STM32746G-Discovery + board. + - This driver does not need a specific component driver for the micro SD device + to be included with. + + 2. Driver description: + --------------------- + + Initialization steps: + o Initialize the micro SD card using the BSP_SD_Init() function. This + function includes the MSP layer hardware resources initialization and the + SDIO interface configuration to interface with the external micro SD. It + also includes the micro SD initialization sequence. + o To check the SD card presence you can use the function BSP_SD_IsDetected() which + returns the detection status + o If SD presence detection interrupt mode is desired, you must configure the + SD detection interrupt mode by calling the function BSP_SD_ITConfig(). The interrupt + is generated as an external interrupt whenever the micro SD card is + plugged/unplugged in/from the board. + o The function BSP_SD_GetCardInfo() is used to get the micro SD card information + which is stored in the structure "HAL_SD_CardInfoTypedef". + + + Micro SD card operations + o The micro SD card can be accessed with read/write block(s) operations once + it is ready for access. The access can be performed whether using the polling + mode by calling the functions BSP_SD_ReadBlocks()/BSP_SD_WriteBlocks(), or by DMA + transfer using the functions BSP_SD_ReadBlocks_DMA()/BSP_SD_WriteBlocks_DMA() + o The DMA transfer complete is used with interrupt mode. Once the SD transfer + is complete, the SD interrupt is handled using the function BSP_SD_IRQHandler(), + the DMA Tx/Rx transfer complete are handled using the functions + BSP_SD_DMA_Tx_IRQHandler()/BSP_SD_DMA_Rx_IRQHandler(). The corresponding user callbacks + are implemented by the user at application level. + o The SD erase block(s) is performed using the function BSP_SD_Erase() with specifying + the number of blocks to erase. + o The SD runtime status is returned when calling the function BSP_SD_GetCardState(). + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32746g_discovery.c +- stm32f7xx_hal_sd.c +- stm32f7xx_ll_sdmmc.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32746g_discovery_sd.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_SD STM32746G_DISCOVERY_SD + * @{ + */ + + +/** @defgroup STM32746G_DISCOVERY_SD_Private_TypesDefinitions STM32746G_DISCOVERY_SD Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_SD_Private_Defines STM32746G_DISCOVERY_SD Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_SD_Private_Macros STM32746G_DISCOVERY_SD Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_SD_Private_Variables STM32746G_DISCOVERY_SD Private Variables + * @{ + */ +SD_HandleTypeDef uSdHandle; + +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_SD_Private_FunctionPrototypes STM32746G_DISCOVERY_SD Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_SD_Exported_Functions STM32746G_DISCOVERY_SD Exported Functions + * @{ + */ + +/** + * @brief Initializes the SD card device. + * @retval SD status + */ +uint8_t BSP_SD_Init(void) +{ + uint8_t sd_state = MSD_OK; + + /* uSD device interface configuration */ + uSdHandle.Instance = SDMMC1; + + uSdHandle.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + uSdHandle.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE; + uSdHandle.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; + uSdHandle.Init.BusWide = SDMMC_BUS_WIDE_1B; + uSdHandle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + uSdHandle.Init.ClockDiv = SDMMC_TRANSFER_CLK_DIV; + + /* Msp SD Detect pin initialization */ + BSP_SD_Detect_MspInit(&uSdHandle, NULL); + if(BSP_SD_IsDetected() != SD_PRESENT) /* Check if SD card is present */ + { + return MSD_ERROR_SD_NOT_PRESENT; + } + + /* Msp SD initialization */ + BSP_SD_MspInit(&uSdHandle, NULL); + + /* HAL SD initialization */ + if(HAL_SD_Init(&uSdHandle) != HAL_OK) + { + sd_state = MSD_ERROR; + } + + /* Configure SD Bus width */ + if(sd_state == MSD_OK) + { + /* Enable wide operation */ + if(HAL_SD_ConfigWideBusOperation(&uSdHandle, SDMMC_BUS_WIDE_4B) != HAL_OK) + { + sd_state = MSD_ERROR; + } + else + { + sd_state = MSD_OK; + } + } + + return sd_state; +} + +/** + * @brief DeInitializes the SD card device. + * @retval SD status + */ +uint8_t BSP_SD_DeInit(void) +{ + uint8_t sd_state = MSD_OK; + + uSdHandle.Instance = SDMMC1; + + /* HAL SD deinitialization */ + if(HAL_SD_DeInit(&uSdHandle) != HAL_OK) + { + sd_state = MSD_ERROR; + } + + /* Msp SD deinitialization */ + uSdHandle.Instance = SDMMC1; + BSP_SD_MspDeInit(&uSdHandle, NULL); + + return sd_state; +} + +/** + * @brief Configures Interrupt mode for SD detection pin. + * @retval Returns MSD_OK + */ +uint8_t BSP_SD_ITConfig(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Configure Interrupt mode for SD detection pin */ + gpio_init_structure.Pin = SD_DETECT_PIN; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Mode = GPIO_MODE_IT_RISING_FALLING; + HAL_GPIO_Init(SD_DETECT_GPIO_PORT, &gpio_init_structure); + + /* Enable and set SD detect EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(SD_DETECT_EXTI_IRQn), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(SD_DETECT_EXTI_IRQn)); + + return MSD_OK; +} + +/** + * @brief Detects if SD card is correctly plugged in the memory slot or not. + * @retval Returns if SD is detected or not + */ +uint8_t BSP_SD_IsDetected(void) +{ + __IO uint8_t status = SD_PRESENT; + + /* Check SD card detect pin */ + if (HAL_GPIO_ReadPin(SD_DETECT_GPIO_PORT, SD_DETECT_PIN) == GPIO_PIN_SET) + { + status = SD_NOT_PRESENT; + } + + return status; +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @param Timeout: Timeout for read operation + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + if(HAL_SD_ReadBlocks(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks, Timeout) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @param Timeout: Timeout for write operation + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + if(HAL_SD_WriteBlocks(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks, Timeout) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in DMA mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks) +{ + /* Read block(s) in DMA transfer mode */ + if(HAL_SD_ReadBlocks_DMA(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in DMA mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks) +{ + /* Write block(s) in DMA transfer mode */ + if(HAL_SD_WriteBlocks_DMA(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Erases the specified memory area of the given SD card. + * @param StartAddr: Start byte address + * @param EndAddr: End byte address + * @retval SD status + */ +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr) +{ + if(HAL_SD_Erase(&uSdHandle, StartAddr, EndAddr) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Initializes the SD MSP. + * @param hsd: SD handle + * @param Params + * @retval None + */ +__weak void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params) +{ + static DMA_HandleTypeDef dma_rx_handle; + static DMA_HandleTypeDef dma_tx_handle; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SDIO clock */ + __HAL_RCC_SDMMC1_CLK_ENABLE(); + + /* Enable DMA2 clocks */ + __DMAx_TxRx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF12_SDMMC1; + + /* GPIOC configuration */ + gpio_init_structure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; + HAL_GPIO_Init(GPIOC, &gpio_init_structure); + + /* GPIOD configuration */ + gpio_init_structure.Pin = GPIO_PIN_2; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* NVIC configuration for SDIO interrupts */ + HAL_NVIC_SetPriority(SDMMC1_IRQn, 0x0E, 0); + HAL_NVIC_EnableIRQ(SDMMC1_IRQn); + + /* Configure DMA Rx parameters */ + dma_rx_handle.Init.Channel = SD_DMAx_Rx_CHANNEL; + dma_rx_handle.Init.Direction = DMA_PERIPH_TO_MEMORY; + dma_rx_handle.Init.PeriphInc = DMA_PINC_DISABLE; + dma_rx_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_rx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_rx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_rx_handle.Init.Mode = DMA_PFCTRL; + dma_rx_handle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + dma_rx_handle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + dma_rx_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_rx_handle.Init.MemBurst = DMA_MBURST_INC4; + dma_rx_handle.Init.PeriphBurst = DMA_PBURST_INC4; + + dma_rx_handle.Instance = SD_DMAx_Rx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsd, hdmarx, dma_rx_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_rx_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_rx_handle); + + /* Configure DMA Tx parameters */ + dma_tx_handle.Init.Channel = SD_DMAx_Tx_CHANNEL; + dma_tx_handle.Init.Direction = DMA_MEMORY_TO_PERIPH; + dma_tx_handle.Init.PeriphInc = DMA_PINC_DISABLE; + dma_tx_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_tx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_tx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_tx_handle.Init.Mode = DMA_PFCTRL; + dma_tx_handle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + dma_tx_handle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + dma_tx_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_tx_handle.Init.MemBurst = DMA_MBURST_INC4; + dma_tx_handle.Init.PeriphBurst = DMA_PBURST_INC4; + + dma_tx_handle.Instance = SD_DMAx_Tx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsd, hdmatx, dma_tx_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_tx_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_tx_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD_DMAx_Rx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SD_DMAx_Rx_IRQn); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD_DMAx_Tx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SD_DMAx_Tx_IRQn); +} + +/** + * @brief Initializes the SD Detect pin MSP. + * @param hsd: SD handle + * @param Params + * @retval None + */ +__weak void BSP_SD_Detect_MspInit(SD_HandleTypeDef *hsd, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + SD_DETECT_GPIO_CLK_ENABLE(); + + /* GPIO configuration in input for uSD_Detect signal */ + gpio_init_structure.Pin = SD_DETECT_PIN; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(SD_DETECT_GPIO_PORT, &gpio_init_structure); +} + +/** + * @brief DeInitializes the SD MSP. + * @param hsd: SD handle + * @param Params + * @retval None + */ +__weak void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params) +{ + static DMA_HandleTypeDef dma_rx_handle; + static DMA_HandleTypeDef dma_tx_handle; + + /* Disable NVIC for DMA transfer complete interrupts */ + HAL_NVIC_DisableIRQ(SD_DMAx_Rx_IRQn); + HAL_NVIC_DisableIRQ(SD_DMAx_Tx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_rx_handle.Instance = SD_DMAx_Rx_STREAM; + HAL_DMA_DeInit(&dma_rx_handle); + + /* Deinitialize the stream for new transfer */ + dma_tx_handle.Instance = SD_DMAx_Tx_STREAM; + HAL_DMA_DeInit(&dma_tx_handle); + + /* Disable NVIC for SDIO interrupts */ + HAL_NVIC_DisableIRQ(SDMMC1_IRQn); + + /* DeInit GPIO pins can be done in the application + (by surcharging this __weak function) */ + + /* Disable SDMMC1 clock */ + __HAL_RCC_SDMMC1_CLK_DISABLE(); + + /* GPIO pins clock and DMA clocks can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Gets the current SD card data status. + * @retval Data transfer state. + * This value can be one of the following values: + * @arg SD_TRANSFER_OK: No data transfer is acting + * @arg SD_TRANSFER_BUSY: Data transfer is acting + */ +uint8_t BSP_SD_GetCardState(void) +{ + return((HAL_SD_GetCardState(&uSdHandle) == HAL_SD_CARD_TRANSFER ) ? SD_TRANSFER_OK : SD_TRANSFER_BUSY); +} + + +/** + * @brief Get SD information about specific SD card. + * @param CardInfo: Pointer to HAL_SD_CardInfoTypedef structure + * @retval None + */ +void BSP_SD_GetCardInfo(HAL_SD_CardInfoTypeDef *CardInfo) +{ + /* Get SD card Information */ + HAL_SD_GetCardInfo(&uSdHandle, CardInfo); +} + +/** + * @brief SD Abort callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_AbortCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_AbortCallback(); +} + +/** + * @brief Tx Transfer completed callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_WriteCpltCallback(); +} + +/** + * @brief Rx Transfer completed callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_ReadCpltCallback(); +} + +/** + * @brief BSP SD Abort callbacks + * @retval None + */ +__weak void BSP_SD_AbortCallback(void) +{ + +} + +/** + * @brief BSP Tx Transfer completed callbacks + * @retval None + */ +__weak void BSP_SD_WriteCpltCallback(void) +{ + +} + +/** + * @brief BSP Rx Transfer completed callbacks + * @retval None + */ +__weak void BSP_SD_ReadCpltCallback(void) +{ + +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sd.h b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sd.h new file mode 100644 index 00000000..9c435df9 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sd.h @@ -0,0 +1,161 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_sd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32746g_discovery_sd.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32746G_DISCOVERY_SD_H +#define __STM32746G_DISCOVERY_SD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32746g_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY_SD + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_SD_Exported_Types STM32746G_DISCOVERY_SD Exported Types + * @{ + */ + +/** + * @brief SD Card information structure + */ +#define BSP_SD_CardInfo HAL_SD_CardInfoTypeDef +/** + * @} + */ + +/** + * @brief SD status structure definition + */ +#define MSD_OK ((uint8_t)0x00) +#define MSD_ERROR ((uint8_t)0x01) +#define MSD_ERROR_SD_NOT_PRESENT ((uint8_t)0x02) + +/** + * @brief SD transfer state definition + */ +#define SD_TRANSFER_OK ((uint8_t)0x00) +#define SD_TRANSFER_BUSY ((uint8_t)0x01) + +/** @defgroup STM32746G_DISCOVERY_SD_Exported_Constants STM32746G_DISCOVERY_SD Exported Constants + * @{ + */ +#define SD_PRESENT ((uint8_t)0x01) +#define SD_NOT_PRESENT ((uint8_t)0x00) + +#define SD_DATATIMEOUT ((uint32_t)100000000) + +/* DMA definitions for SD DMA transfer */ +#define __DMAx_TxRx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define SD_DMAx_Tx_CHANNEL DMA_CHANNEL_4 +#define SD_DMAx_Rx_CHANNEL DMA_CHANNEL_4 +#define SD_DMAx_Tx_STREAM DMA2_Stream6 +#define SD_DMAx_Rx_STREAM DMA2_Stream3 +#define SD_DMAx_Tx_IRQn DMA2_Stream6_IRQn +#define SD_DMAx_Rx_IRQn DMA2_Stream3_IRQn +#define BSP_SDMMC_IRQHandler SDMMC1_IRQHandler +#define BSP_SDMMC_DMA_Tx_IRQHandler DMA2_Stream6_IRQHandler +#define BSP_SDMMC_DMA_Rx_IRQHandler DMA2_Stream3_IRQHandler +#define SD_DetectIRQHandler() HAL_GPIO_EXTI_IRQHandler(SD_DETECT_PIN) +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_SD_Exported_Macro STM32746G_DISCOVERY_SD Exported Macro + * @{ + */ +/** + * @} + */ + +/** @addtogroup STM32746G_DISCOVERY_SD_Exported_Functions + * @{ + */ +uint8_t BSP_SD_Init(void); +uint8_t BSP_SD_DeInit(void); +uint8_t BSP_SD_ITConfig(void); +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks); +uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks); +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); +uint8_t BSP_SD_GetCardState(void); +void BSP_SD_GetCardInfo(HAL_SD_CardInfoTypeDef *CardInfo); +uint8_t BSP_SD_IsDetected(void); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_Detect_MspInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_AbortCallback(void); +void BSP_SD_WriteCpltCallback(void); +void BSP_SD_ReadCpltCallback(void); +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32746G_DISCOVERY_SD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sdram.c b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sdram.c new file mode 100644 index 00000000..80e4370a --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sdram.c @@ -0,0 +1,497 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_sdram.c + * @author MCD Application Team + * @brief This file includes the SDRAM driver for the MT48LC4M32B2B5-7 memory + * device mounted on STM32746G-Discovery board. + @verbatim + 1. How To use this driver: + -------------------------- + - This driver is used to drive the MT48LC4M32B2B5-7 SDRAM external memory mounted + on STM32746G-Discovery board. + - This driver does not need a specific component driver for the SDRAM device + to be included with. + + 2. Driver description: + --------------------- + + Initialization steps: + o Initialize the SDRAM external memory using the BSP_SDRAM_Init() function. This + function includes the MSP layer hardware resources initialization and the + FMC controller configuration to interface with the external SDRAM memory. + o It contains the SDRAM initialization sequence to program the SDRAM external + device using the function BSP_SDRAM_Initialization_sequence(). Note that this + sequence is standard for all SDRAM devices, but can include some differences + from a device to another. If it is the case, the right sequence should be + implemented separately. + + + SDRAM read/write operations + o SDRAM external memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_SDRAM_ReadData()/BSP_SDRAM_WriteData(), or by DMA transfer using the functions + BSP_SDRAM_ReadData_DMA()/BSP_SDRAM_WriteData_DMA(). + o The AHB access is performed with 32-bit width transaction, the DMA transfer + configuration is fixed at single (no burst) word transfer (see the + SDRAM_MspInit() static function). + o User can implement his own functions for read/write access with his desired + configurations. + o If interrupt mode is used for DMA transfer, the function BSP_SDRAM_DMA_IRQHandler() + is called in IRQ handler file, to serve the generated interrupt once the DMA + transfer is complete. + o You can send a command to the SDRAM device in runtime using the function + BSP_SDRAM_Sendcmd(), and giving the desired command as parameter chosen between + the predefined commands of the "FMC_SDRAM_CommandTypeDef" structure. + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_sdram.c +- stm32f7xx_ll_fmc.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32746g_discovery_sdram.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_SDRAM STM32746G_DISCOVERY_SDRAM + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_SDRAM_Private_Types_Definitions STM32746G_DISCOVERY_SDRAM Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_SDRAM_Private_Defines STM32746G_DISCOVERY_SDRAM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_SDRAM_Private_Macros STM32746G_DISCOVERY_SDRAM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_SDRAM_Private_Variables STM32746G_DISCOVERY_SDRAM Private Variables + * @{ + */ +SDRAM_HandleTypeDef sdramHandle; +static FMC_SDRAM_TimingTypeDef Timing; +static FMC_SDRAM_CommandTypeDef Command; +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_SDRAM_Private_Function_Prototypes STM32746G_DISCOVERY_SDRAM Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_SDRAM_Exported_Functions STM32746G_DISCOVERY_SDRAM Exported Functions + * @{ + */ + +/** + * @brief Initializes the SDRAM device. + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_Init(void) +{ + static uint8_t sdramstatus = SDRAM_ERROR; + /* SDRAM device configuration */ + sdramHandle.Instance = FMC_SDRAM_DEVICE; + + /* Timing configuration for 100Mhz as SD clock frequency (System clock is up to 200Mhz) */ + Timing.LoadToActiveDelay = 2; + Timing.ExitSelfRefreshDelay = 7; + Timing.SelfRefreshTime = 4; + Timing.RowCycleDelay = 7; + Timing.WriteRecoveryTime = 2; + Timing.RPDelay = 2; + Timing.RCDDelay = 2; + + sdramHandle.Init.SDBank = FMC_SDRAM_BANK1; + sdramHandle.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8; + sdramHandle.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; + sdramHandle.Init.MemoryDataWidth = SDRAM_MEMORY_WIDTH; + sdramHandle.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; + sdramHandle.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2; + sdramHandle.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; + sdramHandle.Init.SDClockPeriod = SDCLOCK_PERIOD; + sdramHandle.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE; + sdramHandle.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; + + /* SDRAM controller initialization */ + + BSP_SDRAM_MspInit(&sdramHandle, NULL); /* __weak function can be rewritten by the application */ + + if(HAL_SDRAM_Init(&sdramHandle, &Timing) != HAL_OK) + { + sdramstatus = SDRAM_ERROR; + } + else + { + sdramstatus = SDRAM_OK; + } + + /* SDRAM initialization sequence */ + BSP_SDRAM_Initialization_sequence(REFRESH_COUNT); + + return sdramstatus; +} + +/** + * @brief DeInitializes the SDRAM device. + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_DeInit(void) +{ + static uint8_t sdramstatus = SDRAM_ERROR; + /* SDRAM device de-initialization */ + sdramHandle.Instance = FMC_SDRAM_DEVICE; + + if(HAL_SDRAM_DeInit(&sdramHandle) != HAL_OK) + { + sdramstatus = SDRAM_ERROR; + } + else + { + sdramstatus = SDRAM_OK; + } + + /* SDRAM controller de-initialization */ + BSP_SDRAM_MspDeInit(&sdramHandle, NULL); + + return sdramstatus; +} + +/** + * @brief Programs the SDRAM device. + * @param RefreshCount: SDRAM refresh counter value + * @retval None + */ +void BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount) +{ + __IO uint32_t tmpmrd = 0; + + /* Step 1: Configure a clock configuration enable command */ + Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 2: Insert 100 us minimum delay */ + /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */ + HAL_Delay(1); + + /* Step 3: Configure a PALL (precharge all) command */ + Command.CommandMode = FMC_SDRAM_CMD_PALL; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 4: Configure an Auto Refresh command */ + Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 8; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 5: Program the external memory mode register */ + tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |\ + SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |\ + SDRAM_MODEREG_CAS_LATENCY_2 |\ + SDRAM_MODEREG_OPERATING_MODE_STANDARD |\ + SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; + + Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = tmpmrd; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 6: Set the refresh rate counter */ + /* Set the device refresh rate */ + HAL_SDRAM_ProgramRefreshRate(&sdramHandle, RefreshCount); +} + +/** + * @brief Reads an amount of data from the SDRAM memory in polling mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_ReadData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Read_32b(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Reads an amount of data from the SDRAM memory in DMA mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_ReadData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Read_DMA(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Writes an amount of data to the SDRAM memory in polling mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_WriteData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Write_32b(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Writes an amount of data to the SDRAM memory in DMA mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_WriteData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Write_DMA(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Sends command to the SDRAM bank. + * @param SdramCmd: Pointer to SDRAM command structure + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_Sendcmd(FMC_SDRAM_CommandTypeDef *SdramCmd) +{ + if(HAL_SDRAM_SendCommand(&sdramHandle, SdramCmd, SDRAM_TIMEOUT) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Initializes SDRAM MSP. + * @param hsdram: SDRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable FMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + + /* Enable chosen DMAx clock */ + __DMAx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = GPIO_AF12_FMC; + + /* GPIOC configuration */ + gpio_init_structure.Pin = GPIO_PIN_3; + HAL_GPIO_Init(GPIOC, &gpio_init_structure); + + /* GPIOD configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8 | GPIO_PIN_9 | + GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOE configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7| GPIO_PIN_8 | GPIO_PIN_9 |\ + GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\ + GPIO_PIN_15; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOF configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\ + GPIO_PIN_15; + HAL_GPIO_Init(GPIOF, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4| GPIO_PIN_5 | GPIO_PIN_8 |\ + GPIO_PIN_15; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + /* GPIOH configuration */ + gpio_init_structure.Pin = GPIO_PIN_3 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOH, &gpio_init_structure); + + /* Configure common DMA parameters */ + dma_handle.Init.Channel = SDRAM_DMAx_CHANNEL; + dma_handle.Init.Direction = DMA_MEMORY_TO_MEMORY; + dma_handle.Init.PeriphInc = DMA_PINC_ENABLE; + dma_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_handle.Init.Mode = DMA_NORMAL; + dma_handle.Init.Priority = DMA_PRIORITY_HIGH; + dma_handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + dma_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_handle.Init.MemBurst = DMA_MBURST_SINGLE; + dma_handle.Init.PeriphBurst = DMA_PBURST_SINGLE; + + dma_handle.Instance = SDRAM_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsdram, hdma, dma_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SDRAM_DMAx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SDRAM_DMAx_IRQn); +} + +/** + * @brief DeInitializes SDRAM MSP. + * @param hsdram: SDRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SDRAM_MspDeInit(SDRAM_HandleTypeDef *hsdram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + + /* Disable NVIC configuration for DMA interrupt */ + HAL_NVIC_DisableIRQ(SDRAM_DMAx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_handle.Instance = SDRAM_DMAx_STREAM; + HAL_DMA_DeInit(&dma_handle); + + /* GPIO pins clock, FMC clock and DMA clock can be shut down in the applications + by surcharging this __weak function */ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sdram.h b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sdram.h new file mode 100644 index 00000000..304217d3 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_sdram.h @@ -0,0 +1,162 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_sdram.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32746g_discovery_sdram.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32746G_DISCOVERY_SDRAM_H +#define __STM32746G_DISCOVERY_SDRAM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY_SDRAM + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_SDRAM_Exported_Types STM32746G_DISCOVERY_SDRAM Exported Types + * @{ + */ + +/** + * @brief SDRAM status structure definition + */ +#define SDRAM_OK ((uint8_t)0x00) +#define SDRAM_ERROR ((uint8_t)0x01) + +/** @defgroup STM32746G_DISCOVERY_SDRAM_Exported_Constants STM32746G_DISCOVERY_SDRAM Exported Constants + * @{ + */ +#define SDRAM_DEVICE_ADDR ((uint32_t)0xC0000000) +#define SDRAM_DEVICE_SIZE ((uint32_t)0x800000) /* SDRAM device size in MBytes */ + +/* #define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_8 */ +#define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_16 + +#define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_2 +/* #define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_3 */ + +#define REFRESH_COUNT ((uint32_t)0x0603) /* SDRAM refresh counter (100Mhz SD clock) */ + +#define SDRAM_TIMEOUT ((uint32_t)0xFFFF) + +/* DMA definitions for SDRAM DMA transfer */ +#define __DMAx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define __DMAx_CLK_DISABLE __HAL_RCC_DMA2_CLK_DISABLE +#define SDRAM_DMAx_CHANNEL DMA_CHANNEL_0 +#define SDRAM_DMAx_STREAM DMA2_Stream0 +#define SDRAM_DMAx_IRQn DMA2_Stream0_IRQn +#define BSP_SDRAM_DMA_IRQHandler DMA2_Stream0_IRQHandler +/** + * @} + */ + +/** + * @brief FMC SDRAM Mode definition register defines + */ +#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) +#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) +#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) +#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) +#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) +#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) +#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_SDRAM_Exported_Macro STM32746G_DISCOVERY_SDRAM Exported Macro + * @{ + */ +/** + * @} + */ + +/** @addtogroup STM32746G_DISCOVERY_SDRAM_Exported_Functions + * @{ + */ +uint8_t BSP_SDRAM_Init(void); +uint8_t BSP_SDRAM_DeInit(void); +void BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount); +uint8_t BSP_SDRAM_ReadData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_ReadData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_WriteData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_WriteData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_Sendcmd(FMC_SDRAM_CommandTypeDef *SdramCmd); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram, void *Params); +void BSP_SDRAM_MspDeInit(SDRAM_HandleTypeDef *hsdram, void *Params); + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32746G_DISCOVERY_SDRAM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_ts.c b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_ts.c new file mode 100644 index 00000000..3bcc5617 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_ts.c @@ -0,0 +1,450 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_ts.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the Touch + * Screen on STM32746G-Discovery board. + @verbatim + 1. How To use this driver: + -------------------------- + - This driver is used to drive the touch screen module of the STM32746G-Discovery + board on the RK043FN48H-CT672B 480x272 LCD screen with capacitive touch screen. + - The FT5336 component driver must be included in project files according to + the touch screen driver present on this board. + + 2. Driver description: + --------------------- + + Initialization steps: + o Initialize the TS module using the BSP_TS_Init() function. This + function includes the MSP layer hardware resources initialization and the + communication layer configuration to start the TS use. The LCD size properties + (x and y) are passed as parameters. + o If TS interrupt mode is desired, you must configure the TS interrupt mode + by calling the function BSP_TS_ITConfig(). The TS interrupt mode is generated + as an external interrupt whenever a touch is detected. + The interrupt mode internally uses the IO functionalities driver driven by + the IO expander, to configure the IT line. + + + Touch screen use + o The touch screen state is captured whenever the function BSP_TS_GetState() is + used. This function returns information about the last LCD touch occurred + in the TS_StateTypeDef structure. + o If TS interrupt mode is used, the function BSP_TS_ITGetStatus() is needed to get + the interrupt status. To clear the IT pending bits, you should call the + function BSP_TS_ITClear(). + o The IT is handled using the corresponding external interrupt IRQ handler, + the user IT callback treatment is implemented on the same external interrupt + callback. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32746g_discovery_lcd.c +- ft5336.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32746g_discovery_ts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_TS STM32746G_DISCOVERY_TS + * @{ + */ + +/** @defgroup STM32746G_DISCOVERY_TS_Private_Types_Definitions STM32746G_DISCOVERY_TS Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_TS_Private_Defines STM32746G_DISCOVERY_TS Types Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_TS_Private_Macros STM32746G_DISCOVERY_TS Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_TS_Imported_Variables STM32746G_DISCOVERY_TS Imported Variables + * @{ + */ + /** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_TS_Private_Variables STM32746G_DISCOVERY_TS Private Variables + * @{ + */ +static TS_DrvTypeDef *tsDriver; +static uint16_t tsXBoundary, tsYBoundary; +static uint8_t tsOrientation; +static uint8_t I2cAddress; +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_TS_Private_Function_Prototypes STM32746G_DISCOVERY_TS Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_TS_Exported_Functions STM32746G_DISCOVERY_TS Exported Functions + * @{ + */ + +/** + * @brief Initializes and configures the touch screen functionalities and + * configures all necessary hardware resources (GPIOs, I2C, clocks..). + * @param ts_SizeX: Maximum X size of the TS area on LCD + * @param ts_SizeY: Maximum Y size of the TS area on LCD + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY) +{ + uint8_t status = TS_OK; + tsXBoundary = ts_SizeX; + tsYBoundary = ts_SizeY; + + /* Read ID and verify if the touch screen driver is ready */ + ft5336_ts_drv.Init(TS_I2C_ADDRESS); + if(ft5336_ts_drv.ReadID(TS_I2C_ADDRESS) == FT5336_ID_VALUE) + { + /* Initialize the TS driver structure */ + tsDriver = &ft5336_ts_drv; + I2cAddress = TS_I2C_ADDRESS; + tsOrientation = TS_SWAP_XY; + + /* Initialize the TS driver */ + tsDriver->Start(I2cAddress); + } + else + { + status = TS_DEVICE_NOT_FOUND; + } + + return status; +} + +/** + * @brief DeInitializes the TouchScreen. + * @retval TS state + */ +uint8_t BSP_TS_DeInit(void) +{ + /* Actually ts_driver does not provide a DeInit function */ + return TS_OK; +} + +/** + * @brief Configures and enables the touch screen interrupts. + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_ITConfig(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Configure Interrupt mode for SD detection pin */ + gpio_init_structure.Pin = TS_INT_PIN; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Mode = GPIO_MODE_IT_RISING; + HAL_GPIO_Init(TS_INT_GPIO_PORT, &gpio_init_structure); + + /* Enable and set Touch screen EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(TS_INT_EXTI_IRQn), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(TS_INT_EXTI_IRQn)); + + /* Enable the TS ITs */ + tsDriver->EnableIT(I2cAddress); + + return TS_OK; +} + +/** + * @brief Gets the touch screen interrupt status. + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_ITGetStatus(void) +{ + /* Return the TS IT status */ + return (tsDriver->GetITStatus(I2cAddress)); +} + +/** + * @brief Returns status and positions of the touch screen. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State) +{ + static uint32_t _x[TS_MAX_NB_TOUCH] = {0, 0}; + static uint32_t _y[TS_MAX_NB_TOUCH] = {0, 0}; + uint8_t ts_status = TS_OK; + uint16_t x[TS_MAX_NB_TOUCH]; + uint16_t y[TS_MAX_NB_TOUCH]; + uint16_t brute_x[TS_MAX_NB_TOUCH]; + uint16_t brute_y[TS_MAX_NB_TOUCH]; + uint16_t x_diff; + uint16_t y_diff; + uint32_t index; +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + uint32_t weight = 0; + uint32_t area = 0; + uint32_t event = 0; +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + /* Check and update the number of touches active detected */ + TS_State->touchDetected = tsDriver->DetectTouch(I2cAddress); + + if(TS_State->touchDetected) + { + for(index=0; index < TS_State->touchDetected; index++) + { + /* Get each touch coordinates */ + tsDriver->GetXY(I2cAddress, &(brute_x[index]), &(brute_y[index])); + + if(tsOrientation == TS_SWAP_NONE) + { + x[index] = brute_x[index]; + y[index] = brute_y[index]; + } + + if(tsOrientation & TS_SWAP_X) + { + x[index] = 4096 - brute_x[index]; + } + + if(tsOrientation & TS_SWAP_Y) + { + y[index] = 4096 - brute_y[index]; + } + + if(tsOrientation & TS_SWAP_XY) + { + y[index] = brute_x[index]; + x[index] = brute_y[index]; + } + + x_diff = x[index] > _x[index]? (x[index] - _x[index]): (_x[index] - x[index]); + y_diff = y[index] > _y[index]? (y[index] - _y[index]): (_y[index] - y[index]); + + if ((x_diff + y_diff) > 5) + { + _x[index] = x[index]; + _y[index] = y[index]; + } + + if(I2cAddress == FT5336_I2C_SLAVE_ADDRESS) + { + TS_State->touchX[index] = x[index]; + TS_State->touchY[index] = y[index]; + } + else + { + /* 2^12 = 4096 : indexes are expressed on a dynamic of 4096 */ + TS_State->touchX[index] = (tsXBoundary * _x[index]) >> 12; + TS_State->touchY[index] = (tsYBoundary * _y[index]) >> 12; + } + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + + /* Get touch info related to the current touch */ + ft5336_TS_GetTouchInfo(I2cAddress, index, &weight, &area, &event); + + /* Update TS_State structure */ + TS_State->touchWeight[index] = weight; + TS_State->touchArea[index] = area; + + /* Remap touch event */ + switch(event) + { + case FT5336_TOUCH_EVT_FLAG_PRESS_DOWN : + TS_State->touchEventId[index] = TOUCH_EVENT_PRESS_DOWN; + break; + case FT5336_TOUCH_EVT_FLAG_LIFT_UP : + TS_State->touchEventId[index] = TOUCH_EVENT_LIFT_UP; + break; + case FT5336_TOUCH_EVT_FLAG_CONTACT : + TS_State->touchEventId[index] = TOUCH_EVENT_CONTACT; + break; + case FT5336_TOUCH_EVT_FLAG_NO_EVENT : + TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT; + break; + default : + ts_status = TS_ERROR; + break; + } /* of switch(event) */ + +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + } /* of for(index=0; index < TS_State->touchDetected; index++) */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + /* Get gesture Id */ + ts_status = BSP_TS_Get_GestureId(TS_State); +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + } /* end of if(TS_State->touchDetected != 0) */ + + return (ts_status); +} + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +/** + * @brief Update gesture Id following a touch detected. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State) +{ + uint32_t gestureId = 0; + uint8_t ts_status = TS_OK; + + /* Get gesture Id */ + ft5336_TS_GetGestureID(I2cAddress, &gestureId); + + /* Remap gesture Id to a TS_GestureIdTypeDef value */ + switch(gestureId) + { + case FT5336_GEST_ID_NO_GESTURE : + TS_State->gestureId = GEST_ID_NO_GESTURE; + break; + case FT5336_GEST_ID_MOVE_UP : + TS_State->gestureId = GEST_ID_MOVE_UP; + break; + case FT5336_GEST_ID_MOVE_RIGHT : + TS_State->gestureId = GEST_ID_MOVE_RIGHT; + break; + case FT5336_GEST_ID_MOVE_DOWN : + TS_State->gestureId = GEST_ID_MOVE_DOWN; + break; + case FT5336_GEST_ID_MOVE_LEFT : + TS_State->gestureId = GEST_ID_MOVE_LEFT; + break; + case FT5336_GEST_ID_ZOOM_IN : + TS_State->gestureId = GEST_ID_ZOOM_IN; + break; + case FT5336_GEST_ID_ZOOM_OUT : + TS_State->gestureId = GEST_ID_ZOOM_OUT; + break; + default : + ts_status = TS_ERROR; + break; + } /* of switch(gestureId) */ + + return(ts_status); +} +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +/** + * @brief Clears all touch screen interrupts. + */ +void BSP_TS_ITClear(void) +{ + /* Clear TS IT pending bits */ + tsDriver->ClearIT(I2cAddress); +} + + +/** @defgroup STM32756G_DISCOVERY_TS_Private_Functions TS Private Functions + * @{ + */ + + +/** + * @brief Function used to reset all touch data before a new acquisition + * of touch information. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if OK, TE_ERROR if problem found. + */ +uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State) +{ + uint8_t ts_status = TS_ERROR; + uint32_t index; + + if (TS_State != (TS_StateTypeDef *)NULL) + { + TS_State->gestureId = GEST_ID_NO_GESTURE; + TS_State->touchDetected = 0; + + for(index = 0; index < TS_MAX_NB_TOUCH; index++) + { + TS_State->touchX[index] = 0; + TS_State->touchY[index] = 0; + TS_State->touchArea[index] = 0; + TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT; + TS_State->touchWeight[index] = 0; + } + + ts_status = TS_OK; + + } /* of if (TS_State != (TS_StateTypeDef *)NULL) */ + + return (ts_status); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_ts.h b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_ts.h new file mode 100644 index 00000000..41ae7978 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32746G-Discovery/stm32746g_discovery_ts.h @@ -0,0 +1,212 @@ +/** + ****************************************************************************** + * @file stm32746g_discovery_ts.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32746g_discovery_ts.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32746G_DISCOVERY_TS_H +#define __STM32746G_DISCOVERY_TS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32746g_discovery.h" +/* Include touch screen FT5336 component Driver */ +#include "../Components/ft5336/ft5336.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY + * @{ + */ + +/** @addtogroup STM32746G_DISCOVERY_TS + * @{ + */ + + /** @defgroup STM32746G_DISCOVERY_TS_Exported_Constants STM32746G_DISCOVERY_TS Exported Constants + * @{ + */ + +/** @brief With FT5336 : maximum 5 touches detected simultaneously + */ +#define TS_MAX_NB_TOUCH ((uint32_t) FT5336_MAX_DETECTABLE_TOUCH) + +#define TS_NO_IRQ_PENDING ((uint8_t) 0) +#define TS_IRQ_PENDING ((uint8_t) 1) + +#define TS_SWAP_NONE ((uint8_t) 0x01) +#define TS_SWAP_X ((uint8_t) 0x02) +#define TS_SWAP_Y ((uint8_t) 0x04) +#define TS_SWAP_XY ((uint8_t) 0x08) + +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_TS_Exported_Types STM32746G_DISCOVERY_TS Exported Types + * @{ + */ +/** +* @brief TS_StateTypeDef +* Define TS State structure +*/ +typedef struct +{ + uint8_t touchDetected; /*!< Total number of active touches detected at last scan */ + uint16_t touchX[TS_MAX_NB_TOUCH]; /*!< Touch X[0], X[1] coordinates on 12 bits */ + uint16_t touchY[TS_MAX_NB_TOUCH]; /*!< Touch Y[0], Y[1] coordinates on 12 bits */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + uint8_t touchWeight[TS_MAX_NB_TOUCH]; /*!< Touch_Weight[0], Touch_Weight[1] : weight property of touches */ + uint8_t touchEventId[TS_MAX_NB_TOUCH]; /*!< Touch_EventId[0], Touch_EventId[1] : take value of type @ref TS_TouchEventTypeDef */ + uint8_t touchArea[TS_MAX_NB_TOUCH]; /*!< Touch_Area[0], Touch_Area[1] : touch area of each touch */ + uint32_t gestureId; /*!< type of gesture detected : take value of type @ref TS_GestureIdTypeDef */ +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +} TS_StateTypeDef; + +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_TS_Exported_Constants STM32746G_DISCOVERY_TS Exported Constants + * @{ + */ + +typedef enum +{ + TS_OK = 0x00, /*!< Touch Ok */ + TS_ERROR = 0x01, /*!< Touch Error */ + TS_TIMEOUT = 0x02, /*!< Touch Timeout */ + TS_DEVICE_NOT_FOUND = 0x03 /*!< Touchscreen device not found */ +}TS_StatusTypeDef; + +/** + * @brief TS_GestureIdTypeDef + * Define Possible managed gesture identification values returned by touch screen + * driver. + */ +typedef enum +{ + GEST_ID_NO_GESTURE = 0x00, /*!< Gesture not defined / recognized */ + GEST_ID_MOVE_UP = 0x01, /*!< Gesture Move Up */ + GEST_ID_MOVE_RIGHT = 0x02, /*!< Gesture Move Right */ + GEST_ID_MOVE_DOWN = 0x03, /*!< Gesture Move Down */ + GEST_ID_MOVE_LEFT = 0x04, /*!< Gesture Move Left */ + GEST_ID_ZOOM_IN = 0x05, /*!< Gesture Zoom In */ + GEST_ID_ZOOM_OUT = 0x06, /*!< Gesture Zoom Out */ + GEST_ID_NB_MAX = 0x07 /*!< max number of gesture id */ + +} TS_GestureIdTypeDef; + +/** + * @brief TS_TouchEventTypeDef + * Define Possible touch events kind as returned values + * by touch screen IC Driver. + */ +typedef enum +{ + TOUCH_EVENT_NO_EVT = 0x00, /*!< Touch Event : undetermined */ + TOUCH_EVENT_PRESS_DOWN = 0x01, /*!< Touch Event Press Down */ + TOUCH_EVENT_LIFT_UP = 0x02, /*!< Touch Event Lift Up */ + TOUCH_EVENT_CONTACT = 0x03, /*!< Touch Event Contact */ + TOUCH_EVENT_NB_MAX = 0x04 /*!< max number of touch events kind */ + +} TS_TouchEventTypeDef; +/** + * @} + */ + +/** @defgroup STM32746G_DISCOVERY_TS_Imported_Variables STM32746G_DISCOVERY_TS Imported Variables + * @{ + */ +/** + * @brief Table for touchscreen event information display on LCD : + * table indexed on enum @ref TS_TouchEventTypeDef information + */ +extern char * ts_event_string_tab[TOUCH_EVENT_NB_MAX]; + +/** + * @brief Table for touchscreen gesture Id information display on LCD : table indexed + * on enum @ref TS_GestureIdTypeDef information + */ +extern char * ts_gesture_id_string_tab[GEST_ID_NB_MAX]; +/** + * @} + */ + +/** @addtogroup STM32746G_DISCOVERY_TS_Exported_Functions + * @{ + */ +uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY); +uint8_t BSP_TS_DeInit(void); +uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State); + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State); +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +uint8_t BSP_TS_ITConfig(void); +uint8_t BSP_TS_ITGetStatus(void); +void BSP_TS_ITClear(void); +uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State); +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32746G_DISCOVERY_TS_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/Release_Notes.html new file mode 100644 index 00000000..65ce8e16 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/Release_Notes.html @@ -0,0 +1,210 @@ + + + + + + + Release Notes for STM32756G-EVAL and STM32746G-EVAL BSP Drivers + + + + + +
+
+
+
+
+

Release Notes for STM32756G-EVAL and STM32746G-EVAL BSP Drivers

+

Copyright © 2015 STMicroelectronics
+

+ +
+
+
+

License

+This software component is licensed by ST under BSD 3-Clause license, the “Licenseâ€; You may not use this component except in compliance with the License. You may obtain a copy of the License at: +
+https://opensource.org/licenses/BSD-3-Clause +
+

Purpose

+

The BSP (Board Specific Package) drivers are parts of the STM32Cube package based on the HAL drivers and provide a set of high level APIs relative to the hardware components and features in the evaluation boards, discovery kits and nucleo boards coming with the STM32Cube package for a given STM32 serie.

+

The BSP drivers allow a quick access to the boards’ services using high level APIs and without any specific configuration as the link with the HAL and the external components is done in intrinsic within the drivers.

+

From project settings points of view, user has only to add the necessary driver’s files in the workspace and call the needed functions from examples. However some low level configuration functions are weak and can be overridden by the applications if user wants to change some BSP drivers default behavior.

+
+
+

Update History

+
+ +
+

Main Changes

+
    +
  • stm32756g_eval_camera.c/.h: +
      +
    • Support ov5640 camera sensor
    • +
  • +
  • stm32756g_eval.c/.h: +
      +
    • Add OV5640 I2C address
    • +
    • Update CAMERA IO Read/Write to support ov5640 camera sensor
    • +
  • +
  • stm32756g_eval_nor.c: +
      +
    • Support MT28EW128ABA1LPC NOR Flash
    • +
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • stm32756g_eval_audio.c: +
      +
    • Aligned with PDM library v3.0.0
    • +
  • +
+

Dependencies

+
    +
  • This version must be used with v3.0.0 of PDM library
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • stm32756g_eval_lcd.c: +
      +
    • Fix compilation errors with SW4STM32 toolchain.
    • +
  • +
  • stm32756g_eval.c: +
      +
    • Upgrade version to v2.0.2
    • +
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • Add general description of BSP drivers
  • +
  • Add Dependencies section
  • +
  • Support of PDSC
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • stm32756g_eval_sd.c/.h: +
      +
    • Update BSP SD APIs following new HAL SD drivers implementation
    • +
    • Fix BlockSize to 512 bytes
    • +
  • +
  • stm32756g_eval_ts.c/.h: +
      +
    • Update TS_INT_PIN define
    • +
  • +
  • stm32756g_eval_lcd.c/.h: +
      +
    • Update BSP_LCD_ReadPixel to read correctly ARGB8888 and RGB888 pixels
    • +
  • +
  • stm32756g_eval_qspi.c/.h: +
      +
    • QSPI write operation improvement
    • +
    • Update CS High Time
    • +
  • +
+

Backward compatibility

+
    +
  • These BSP drivers break the compatibility with previous versions.
  • +
+

Dependencies

+
    +
  • If FatFs is required, “FatFS R0.11 ST modified 20161223†must be used with this version of BSP drivers.
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • Update typos in drivers comments.
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • Update overall drivers by removing BSP_PPP_IRQHandler, BSP_PPP_DMA_TX_IRQHandler and BSP_PPP_DMA_RX_IRQHandler to avoid possible conflict when the same Handler is used by different IPs.
  • +
  • These Handlers should be defined by user at application level, inducing a break of compatibility versus V1.0.1 of the STM32756G-EVAL BSP drivers
  • +
  • Add new functions BSP_POTENTIOMETER_Init() and BSP_POTENTIOMETER_GetLevel()
  • +
  • Update NVIC priority configuration to the lowest priority 0x0F
  • +
  • stm32756g_eval_lcd.c: Add the following APIs: +
      +
    • BSP_LCD_SetTransparency_NoReload()
    • +
    • BSP_LCD_SetLayerAddress_NoReload()
    • +
    • BSP_LCD_SetColorKeying_NoReload()
    • +
    • BSP_LCD_ResetColorKeying_NoReload()
    • +
    • BSP_LCD_SetLayerWindow_NoReload()
    • +
    • BSP_LCD_SetLayerVisible_NoReload()
    • +
    • BSP_LCD_Reload()
    • +
  • +
  • stm32756g_eval_camera.c: +
      +
    • Update BSP_CAMERA_Suspend() and BSP_CAMERA_Resume() APIs to use HAL API HAL_DCMI_Suspend() and HAL_DCMI_Resume()
    • +
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • stm32756g_eval.c +
      +
    • Add AUDIO_IO_DeInit() function to be compatible with common version 4.0.0 or later
    • +
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • First official release of the STM32756G-EVAL and STM32746G-EVAL BSP drivers
  • +
+

Dependencies

+
    +
  • STM32F7xx_HAL_Driver V1.2.0
  • +
  • BSP Common V4.0.1
  • +
  • PDM Library V2.0.1
  • +
+
+
+
+
+
+For complete documentation on STM32756G-EVAL and STM32746G-EVAL , visit: www.st.com +
+ + diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/_htmresc/mini-st.css b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/_htmresc/mini-st.css new file mode 100644 index 00000000..71fbc14f --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/_htmresc/mini-st.css @@ -0,0 +1,1700 @@ +@charset "UTF-8"; +/* + Flavor name: Default (mini-default) + Author: Angelos Chalaris (chalarangelo@gmail.com) + Maintainers: Angelos Chalaris + mini.css version: v3.0.0-alpha.3 +*/ +/* + Browsers resets and base typography. +*/ +/* Core module CSS variable definitions */ +:root { + --fore-color: #111; + --secondary-fore-color: #444; + --back-color: #f8f8f8; + --secondary-back-color: #f0f0f0; + --blockquote-color: #f57c00; + --pre-color: #1565c0; + --border-color: #aaa; + --secondary-border-color: #ddd; + --heading-ratio: 1.19; + --universal-margin: 0.5rem; + --universal-padding: 0.125rem; + --universal-border-radius: 0.125rem; + --a-link-color: #0277bd; + --a-visited-color: #01579b; } + +html { + font-size: 14px; } + +a, b, del, em, i, ins, q, span, strong, u { + font-size: 1em; } + +html, * { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", Helvetica, sans-serif; + line-height: 1.4; + -webkit-text-size-adjust: 100%; } + +* { + font-size: 1rem; } + +body { + margin: 0; + color: var(--fore-color); + background: var(--back-color); } + +details { + display: block; } + +summary { + display: list-item; } + +abbr[title] { + border-bottom: none; + text-decoration: underline dotted; } + +input { + overflow: visible; } + +img { + max-width: 100%; + height: auto; } + +h1, h2, h3, h4, h5, h6 { + line-height: 1.2; + margin: calc(1.5 * var(--universal-margin)) var(--universal-margin); + font-weight: 500; } + h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { + color: var(--secondary-fore-color); + display: block; + margin-top: -0.25rem; } + +h1 { + font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio)); } + +h2 { + font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio); ); + background: var(--mark-back-color); + font-weight: 600; + padding: 0.1em 0.5em 0.2em 0.5em; + color: var(--mark-fore-color); } + +h3 { + font-size: calc(1rem * var(--heading-ratio)); + padding-left: calc(2 * var(--universal-margin)); + /* background: var(--border-color); */ + } + +h4 { + font-size: 1rem;); + padding-left: calc(4 * var(--universal-margin)); } + +h5 { + font-size: 1rem; } + +h6 { + font-size: calc(1rem / var(--heading-ratio)); } + +p { + margin: var(--universal-margin); } + +ol, ul { + margin: var(--universal-margin); + padding-left: calc(6 * var(--universal-margin)); } + +b, strong { + font-weight: 700; } + +hr { + box-sizing: content-box; + border: 0; + line-height: 1.25em; + margin: var(--universal-margin); + height: 0.0625rem; + background: linear-gradient(to right, transparent, var(--border-color) 20%, var(--border-color) 80%, transparent); } + +blockquote { + display: block; + position: relative; + font-style: italic; + color: var(--secondary-fore-color); + margin: var(--universal-margin); + padding: calc(3 * var(--universal-padding)); + border: 0.0625rem solid var(--secondary-border-color); + border-left: 0.375rem solid var(--blockquote-color); + border-radius: 0 var(--universal-border-radius) var(--universal-border-radius) 0; } + blockquote:before { + position: absolute; + top: calc(0rem - var(--universal-padding)); + left: 0; + font-family: sans-serif; + font-size: 3rem; + font-weight: 700; + content: "\201c"; + color: var(--blockquote-color); } + blockquote[cite]:after { + font-style: normal; + font-size: 0.75em; + font-weight: 700; + content: "\a— " attr(cite); + white-space: pre; } + +code, kbd, pre, samp { + font-family: Menlo, Consolas, monospace; + font-size: 0.85em; } + +code { + background: var(--secondary-back-color); + border-radius: var(--universal-border-radius); + padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); } + +kbd { + background: var(--fore-color); + color: var(--back-color); + border-radius: var(--universal-border-radius); + padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); } + +pre { + overflow: auto; + background: var(--secondary-back-color); + padding: calc(1.5 * var(--universal-padding)); + margin: var(--universal-margin); + border: 0.0625rem solid var(--secondary-border-color); + border-left: 0.25rem solid var(--pre-color); + border-radius: 0 var(--universal-border-radius) var(--universal-border-radius) 0; } + +sup, sub, code, kbd { + line-height: 0; + position: relative; + vertical-align: baseline; } + +small, sup, sub, figcaption { + font-size: 0.75em; } + +sup { + top: -0.5em; } + +sub { + bottom: -0.25em; } + +figure { + margin: var(--universal-margin); } + +figcaption { + color: var(--secondary-fore-color); } + +a { + text-decoration: none; } + a:link { + color: var(--a-link-color); } + a:visited { + color: var(--a-visited-color); } + a:hover, a:focus { + text-decoration: underline; } + +/* + Definitions for the grid system, cards and containers. +*/ +.container { + margin: 0 auto; + padding: 0 calc(1.5 * var(--universal-padding)); } + +.row { + box-sizing: border-box; + display: flex; + flex: 0 1 auto; + flex-flow: row wrap; } + +.col-sm, +[class^='col-sm-'], +[class^='col-sm-offset-'], +.row[class*='cols-sm-'] > * { + box-sizing: border-box; + flex: 0 0 auto; + padding: 0 calc(var(--universal-padding) / 2); } + +.col-sm, +.row.cols-sm > * { + max-width: 100%; + flex-grow: 1; + flex-basis: 0; } + +.col-sm-1, +.row.cols-sm-1 > * { + max-width: 8.3333333333%; + flex-basis: 8.3333333333%; } + +.col-sm-offset-0 { + margin-left: 0; } + +.col-sm-2, +.row.cols-sm-2 > * { + max-width: 16.6666666667%; + flex-basis: 16.6666666667%; } + +.col-sm-offset-1 { + margin-left: 8.3333333333%; } + +.col-sm-3, +.row.cols-sm-3 > * { + max-width: 25%; + flex-basis: 25%; } + +.col-sm-offset-2 { + margin-left: 16.6666666667%; } + +.col-sm-4, +.row.cols-sm-4 > * { + max-width: 33.3333333333%; + flex-basis: 33.3333333333%; } + +.col-sm-offset-3 { + margin-left: 25%; } + +.col-sm-5, +.row.cols-sm-5 > * { + max-width: 41.6666666667%; + flex-basis: 41.6666666667%; } + +.col-sm-offset-4 { + margin-left: 33.3333333333%; } + +.col-sm-6, +.row.cols-sm-6 > * { + max-width: 50%; + flex-basis: 50%; } + +.col-sm-offset-5 { + margin-left: 41.6666666667%; } + +.col-sm-7, +.row.cols-sm-7 > * { + max-width: 58.3333333333%; + flex-basis: 58.3333333333%; } + +.col-sm-offset-6 { + margin-left: 50%; } + +.col-sm-8, +.row.cols-sm-8 > * { + max-width: 66.6666666667%; + flex-basis: 66.6666666667%; } + +.col-sm-offset-7 { + margin-left: 58.3333333333%; } + +.col-sm-9, +.row.cols-sm-9 > * { + max-width: 75%; + flex-basis: 75%; } + +.col-sm-offset-8 { + margin-left: 66.6666666667%; } + +.col-sm-10, +.row.cols-sm-10 > * { + max-width: 83.3333333333%; + flex-basis: 83.3333333333%; } + +.col-sm-offset-9 { + margin-left: 75%; } + +.col-sm-11, +.row.cols-sm-11 > * { + max-width: 91.6666666667%; + flex-basis: 91.6666666667%; } + +.col-sm-offset-10 { + margin-left: 83.3333333333%; } + +.col-sm-12, +.row.cols-sm-12 > * { + max-width: 100%; + flex-basis: 100%; } + +.col-sm-offset-11 { + margin-left: 91.6666666667%; } + +.col-sm-normal { + order: initial; } + +.col-sm-first { + order: -999; } + +.col-sm-last { + order: 999; } + +@media screen and (min-width: 500px) { + .col-md, + [class^='col-md-'], + [class^='col-md-offset-'], + .row[class*='cols-md-'] > * { + box-sizing: border-box; + flex: 0 0 auto; + padding: 0 calc(var(--universal-padding) / 2); } + + .col-md, + .row.cols-md > * { + max-width: 100%; + flex-grow: 1; + flex-basis: 0; } + + .col-md-1, + .row.cols-md-1 > * { + max-width: 8.3333333333%; + flex-basis: 8.3333333333%; } + + .col-md-offset-0 { + margin-left: 0; } + + .col-md-2, + .row.cols-md-2 > * { + max-width: 16.6666666667%; + flex-basis: 16.6666666667%; } + + .col-md-offset-1 { + margin-left: 8.3333333333%; } + + .col-md-3, + .row.cols-md-3 > * { + max-width: 25%; + flex-basis: 25%; } + + .col-md-offset-2 { + margin-left: 16.6666666667%; } + + .col-md-4, + .row.cols-md-4 > * { + max-width: 33.3333333333%; + flex-basis: 33.3333333333%; } + + .col-md-offset-3 { + margin-left: 25%; } + + .col-md-5, + .row.cols-md-5 > * { + max-width: 41.6666666667%; + flex-basis: 41.6666666667%; } + + .col-md-offset-4 { + margin-left: 33.3333333333%; } + + .col-md-6, + .row.cols-md-6 > * { + max-width: 50%; + flex-basis: 50%; } + + .col-md-offset-5 { + margin-left: 41.6666666667%; } + + .col-md-7, + .row.cols-md-7 > * { + max-width: 58.3333333333%; + flex-basis: 58.3333333333%; } + + .col-md-offset-6 { + margin-left: 50%; } + + .col-md-8, + .row.cols-md-8 > * { + max-width: 66.6666666667%; + flex-basis: 66.6666666667%; } + + .col-md-offset-7 { + margin-left: 58.3333333333%; } + + .col-md-9, + .row.cols-md-9 > * { + max-width: 75%; + flex-basis: 75%; } + + .col-md-offset-8 { + margin-left: 66.6666666667%; } + + .col-md-10, + .row.cols-md-10 > * { + max-width: 83.3333333333%; + flex-basis: 83.3333333333%; } + + .col-md-offset-9 { + margin-left: 75%; } + + .col-md-11, + .row.cols-md-11 > * { + max-width: 91.6666666667%; + flex-basis: 91.6666666667%; } + + .col-md-offset-10 { + margin-left: 83.3333333333%; } + + .col-md-12, + .row.cols-md-12 > * { + max-width: 100%; + flex-basis: 100%; } + + .col-md-offset-11 { + margin-left: 91.6666666667%; } + + .col-md-normal { + order: initial; } + + .col-md-first { + order: -999; } + + .col-md-last { + order: 999; } } +@media screen and (min-width: 1280px) { + .col-lg, + [class^='col-lg-'], + [class^='col-lg-offset-'], + .row[class*='cols-lg-'] > * { + box-sizing: border-box; + flex: 0 0 auto; + padding: 0 calc(var(--universal-padding) / 2); } + + .col-lg, + .row.cols-lg > * { + max-width: 100%; + flex-grow: 1; + flex-basis: 0; } + + .col-lg-1, + .row.cols-lg-1 > * { + max-width: 8.3333333333%; + flex-basis: 8.3333333333%; } + + .col-lg-offset-0 { + margin-left: 0; } + + .col-lg-2, + .row.cols-lg-2 > * { + max-width: 16.6666666667%; + flex-basis: 16.6666666667%; } + + .col-lg-offset-1 { + margin-left: 8.3333333333%; } + + .col-lg-3, + .row.cols-lg-3 > * { + max-width: 25%; + flex-basis: 25%; } + + .col-lg-offset-2 { + margin-left: 16.6666666667%; } + + .col-lg-4, + .row.cols-lg-4 > * { + max-width: 33.3333333333%; + flex-basis: 33.3333333333%; } + + .col-lg-offset-3 { + margin-left: 25%; } + + .col-lg-5, + .row.cols-lg-5 > * { + max-width: 41.6666666667%; + flex-basis: 41.6666666667%; } + + .col-lg-offset-4 { + margin-left: 33.3333333333%; } + + .col-lg-6, + .row.cols-lg-6 > * { + max-width: 50%; + flex-basis: 50%; } + + .col-lg-offset-5 { + margin-left: 41.6666666667%; } + + .col-lg-7, + .row.cols-lg-7 > * { + max-width: 58.3333333333%; + flex-basis: 58.3333333333%; } + + .col-lg-offset-6 { + margin-left: 50%; } + + .col-lg-8, + .row.cols-lg-8 > * { + max-width: 66.6666666667%; + flex-basis: 66.6666666667%; } + + .col-lg-offset-7 { + margin-left: 58.3333333333%; } + + .col-lg-9, + .row.cols-lg-9 > * { + max-width: 75%; + flex-basis: 75%; } + + .col-lg-offset-8 { + margin-left: 66.6666666667%; } + + .col-lg-10, + .row.cols-lg-10 > * { + max-width: 83.3333333333%; + flex-basis: 83.3333333333%; } + + .col-lg-offset-9 { + margin-left: 75%; } + + .col-lg-11, + .row.cols-lg-11 > * { + max-width: 91.6666666667%; + flex-basis: 91.6666666667%; } + + .col-lg-offset-10 { + margin-left: 83.3333333333%; } + + .col-lg-12, + .row.cols-lg-12 > * { + max-width: 100%; + flex-basis: 100%; } + + .col-lg-offset-11 { + margin-left: 91.6666666667%; } + + .col-lg-normal { + order: initial; } + + .col-lg-first { + order: -999; } + + .col-lg-last { + order: 999; } } +/* Card component CSS variable definitions */ +:root { + --card-back-color: #f8f8f8; + --card-fore-color: #111; + --card-border-color: #ddd; } + +.card { + display: flex; + flex-direction: column; + justify-content: space-between; + align-self: center; + position: relative; + width: 100%; + background: var(--card-back-color); + color: var(--card-fore-color); + border: 0.0625rem solid var(--card-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); + overflow: hidden; } + @media screen and (min-width: 320px) { + .card { + max-width: 320px; } } + .card > .sectione { + background: var(--card-back-color); + color: var(--card-fore-color); + box-sizing: border-box; + margin: 0; + border: 0; + border-radius: 0; + border-bottom: 0.0625rem solid var(--card-border-color); + padding: var(--universal-padding); + width: 100%; } + .card > .sectione.media { + height: 200px; + padding: 0; + -o-object-fit: cover; + object-fit: cover; } + .card > .sectione:last-child { + border-bottom: 0; } + +/* + Custom elements for card elements. +*/ +@media screen and (min-width: 240px) { + .card.small { + max-width: 240px; } } +@media screen and (min-width: 480px) { + .card.large { + max-width: 480px; } } +.card.fluid { + max-width: 100%; + width: auto; } + +.card.warning { +/* --card-back-color: #ffca28; */ + --card-back-color: #e5b8b7; + --card-border-color: #e8b825; } + +.card.error { + --card-back-color: #b71c1c; + --card-fore-color: #f8f8f8; + --card-border-color: #a71a1a; } + +.card > .sectione.dark { + --card-back-color: #e0e0e0; } + +.card > .sectione.double-padded { + padding: calc(1.5 * var(--universal-padding)); } + +/* + Definitions for forms and input elements. +*/ +/* Input_control module CSS variable definitions */ +:root { + --form-back-color: #f0f0f0; + --form-fore-color: #111; + --form-border-color: #ddd; + --input-back-color: #f8f8f8; + --input-fore-color: #111; + --input-border-color: #ddd; + --input-focus-color: #0288d1; + --input-invalid-color: #d32f2f; + --button-back-color: #e2e2e2; + --button-hover-back-color: #dcdcdc; + --button-fore-color: #212121; + --button-border-color: transparent; + --button-hover-border-color: transparent; + --button-group-border-color: rgba(124, 124, 124, 0.54); } + +form { + background: var(--form-back-color); + color: var(--form-fore-color); + border: 0.0625rem solid var(--form-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); + padding: calc(2 * var(--universal-padding)) var(--universal-padding); } + +fieldset { + border: 0.0625rem solid var(--form-border-color); + border-radius: var(--universal-border-radius); + margin: calc(var(--universal-margin) / 4); + padding: var(--universal-padding); } + +legend { + box-sizing: border-box; + display: table; + max-width: 100%; + white-space: normal; + font-weight: 700; + padding: calc(var(--universal-padding) / 2); } + +label { + padding: calc(var(--universal-padding) / 2) var(--universal-padding); } + +.input-group { + display: inline-block; } + .input-group.fluid { + display: flex; + align-items: center; + justify-content: center; } + .input-group.fluid > input { + max-width: 100%; + flex-grow: 1; + flex-basis: 0px; } + @media screen and (max-width: 499px) { + .input-group.fluid { + align-items: stretch; + flex-direction: column; } } + .input-group.vertical { + display: flex; + align-items: stretch; + flex-direction: column; } + .input-group.vertical > input { + max-width: 100%; + flex-grow: 1; + flex-basis: 0px; } + +[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { + height: auto; } + +[type="search"] { + -webkit-appearance: textfield; + outline-offset: -2px; } + +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; } + +input:not([type]), [type="text"], [type="email"], [type="number"], [type="search"], +[type="password"], [type="url"], [type="tel"], [type="checkbox"], [type="radio"], textarea, select { + box-sizing: border-box; + background: var(--input-back-color); + color: var(--input-fore-color); + border: 0.0625rem solid var(--input-border-color); + border-radius: var(--universal-border-radius); + margin: calc(var(--universal-margin) / 2); + padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); } + +input:not([type="button"]):not([type="submit"]):not([type="reset"]):hover, input:not([type="button"]):not([type="submit"]):not([type="reset"]):focus, textarea:hover, textarea:focus, select:hover, select:focus { + border-color: var(--input-focus-color); + box-shadow: none; } +input:not([type="button"]):not([type="submit"]):not([type="reset"]):invalid, input:not([type="button"]):not([type="submit"]):not([type="reset"]):focus:invalid, textarea:invalid, textarea:focus:invalid, select:invalid, select:focus:invalid { + border-color: var(--input-invalid-color); + box-shadow: none; } +input:not([type="button"]):not([type="submit"]):not([type="reset"])[readonly], textarea[readonly], select[readonly] { + background: var(--secondary-back-color); } + +select { + max-width: 100%; } + +option { + overflow: hidden; + text-overflow: ellipsis; } + +[type="checkbox"], [type="radio"] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + position: relative; + height: calc(1rem + var(--universal-padding) / 2); + width: calc(1rem + var(--universal-padding) / 2); + vertical-align: text-bottom; + padding: 0; + flex-basis: calc(1rem + var(--universal-padding) / 2) !important; + flex-grow: 0 !important; } + [type="checkbox"]:checked:before, [type="radio"]:checked:before { + position: absolute; } + +[type="checkbox"]:checked:before { + content: '\2713'; + font-family: sans-serif; + font-size: calc(1rem + var(--universal-padding) / 2); + top: calc(0rem - var(--universal-padding)); + left: calc(var(--universal-padding) / 4); } + +[type="radio"] { + border-radius: 100%; } + [type="radio"]:checked:before { + border-radius: 100%; + content: ''; + top: calc(0.0625rem + var(--universal-padding) / 2); + left: calc(0.0625rem + var(--universal-padding) / 2); + background: var(--input-fore-color); + width: 0.5rem; + height: 0.5rem; } + +:placeholder-shown { + color: var(--input-fore-color); } + +::-ms-placeholder { + color: var(--input-fore-color); + opacity: 0.54; } + +button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; } + +button, html [type="button"], [type="reset"], [type="submit"] { + -webkit-appearance: button; } + +button { + overflow: visible; + text-transform: none; } + +button, [type="button"], [type="submit"], [type="reset"], +a.button, label.button, .button, +a[role="button"], label[role="button"], [role="button"] { + display: inline-block; + background: var(--button-back-color); + color: var(--button-fore-color); + border: 0.0625rem solid var(--button-border-color); + border-radius: var(--universal-border-radius); + padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); + margin: var(--universal-margin); + text-decoration: none; + cursor: pointer; + transition: background 0.3s; } + button:hover, button:focus, [type="button"]:hover, [type="button"]:focus, [type="submit"]:hover, [type="submit"]:focus, [type="reset"]:hover, [type="reset"]:focus, + a.button:hover, + a.button:focus, label.button:hover, label.button:focus, .button:hover, .button:focus, + a[role="button"]:hover, + a[role="button"]:focus, label[role="button"]:hover, label[role="button"]:focus, [role="button"]:hover, [role="button"]:focus { + background: var(--button-hover-back-color); + border-color: var(--button-hover-border-color); } + +input:disabled, input[disabled], textarea:disabled, textarea[disabled], select:disabled, select[disabled], button:disabled, button[disabled], .button:disabled, .button[disabled], [role="button"]:disabled, [role="button"][disabled] { + cursor: not-allowed; + opacity: 0.75; } + +.button-group { + display: flex; + border: 0.0625rem solid var(--button-group-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); } + .button-group > button, .button-group [type="button"], .button-group > [type="submit"], .button-group > [type="reset"], .button-group > .button, .button-group > [role="button"] { + margin: 0; + max-width: 100%; + flex: 1 1 auto; + text-align: center; + border: 0; + border-radius: 0; + box-shadow: none; } + .button-group > :not(:first-child) { + border-left: 0.0625rem solid var(--button-group-border-color); } + @media screen and (max-width: 499px) { + .button-group { + flex-direction: column; } + .button-group > :not(:first-child) { + border: 0; + border-top: 0.0625rem solid var(--button-group-border-color); } } + +/* + Custom elements for forms and input elements. +*/ +button.primary, [type="button"].primary, [type="submit"].primary, [type="reset"].primary, .button.primary, [role="button"].primary { + --button-back-color: #1976d2; + --button-fore-color: #f8f8f8; } + button.primary:hover, button.primary:focus, [type="button"].primary:hover, [type="button"].primary:focus, [type="submit"].primary:hover, [type="submit"].primary:focus, [type="reset"].primary:hover, [type="reset"].primary:focus, .button.primary:hover, .button.primary:focus, [role="button"].primary:hover, [role="button"].primary:focus { + --button-hover-back-color: #1565c0; } + +button.secondary, [type="button"].secondary, [type="submit"].secondary, [type="reset"].secondary, .button.secondary, [role="button"].secondary { + --button-back-color: #d32f2f; + --button-fore-color: #f8f8f8; } + button.secondary:hover, button.secondary:focus, [type="button"].secondary:hover, [type="button"].secondary:focus, [type="submit"].secondary:hover, [type="submit"].secondary:focus, [type="reset"].secondary:hover, [type="reset"].secondary:focus, .button.secondary:hover, .button.secondary:focus, [role="button"].secondary:hover, [role="button"].secondary:focus { + --button-hover-back-color: #c62828; } + +button.tertiary, [type="button"].tertiary, [type="submit"].tertiary, [type="reset"].tertiary, .button.tertiary, [role="button"].tertiary { + --button-back-color: #308732; + --button-fore-color: #f8f8f8; } + button.tertiary:hover, button.tertiary:focus, [type="button"].tertiary:hover, [type="button"].tertiary:focus, [type="submit"].tertiary:hover, [type="submit"].tertiary:focus, [type="reset"].tertiary:hover, [type="reset"].tertiary:focus, .button.tertiary:hover, .button.tertiary:focus, [role="button"].tertiary:hover, [role="button"].tertiary:focus { + --button-hover-back-color: #277529; } + +button.inverse, [type="button"].inverse, [type="submit"].inverse, [type="reset"].inverse, .button.inverse, [role="button"].inverse { + --button-back-color: #212121; + --button-fore-color: #f8f8f8; } + button.inverse:hover, button.inverse:focus, [type="button"].inverse:hover, [type="button"].inverse:focus, [type="submit"].inverse:hover, [type="submit"].inverse:focus, [type="reset"].inverse:hover, [type="reset"].inverse:focus, .button.inverse:hover, .button.inverse:focus, [role="button"].inverse:hover, [role="button"].inverse:focus { + --button-hover-back-color: #111; } + +button.small, [type="button"].small, [type="submit"].small, [type="reset"].small, .button.small, [role="button"].small { + padding: calc(0.5 * var(--universal-padding)) calc(0.75 * var(--universal-padding)); + margin: var(--universal-margin); } + +button.large, [type="button"].large, [type="submit"].large, [type="reset"].large, .button.large, [role="button"].large { + padding: calc(1.5 * var(--universal-padding)) calc(2 * var(--universal-padding)); + margin: var(--universal-margin); } + +/* + Definitions for navigation elements. +*/ +/* Navigation module CSS variable definitions */ +:root { + --header-back-color: #f8f8f8; + --header-hover-back-color: #f0f0f0; + --header-fore-color: #444; + --header-border-color: #ddd; + --nav-back-color: #f8f8f8; + --nav-hover-back-color: #f0f0f0; + --nav-fore-color: #444; + --nav-border-color: #ddd; + --nav-link-color: #0277bd; + --footer-fore-color: #444; + --footer-back-color: #f8f8f8; + --footer-border-color: #ddd; + --footer-link-color: #0277bd; + --drawer-back-color: #f8f8f8; + --drawer-hover-back-color: #f0f0f0; + --drawer-border-color: #ddd; + --drawer-close-color: #444; } + +header { + height: 3.1875rem; + background: var(--header-back-color); + color: var(--header-fore-color); + border-bottom: 0.0625rem solid var(--header-border-color); + padding: calc(var(--universal-padding) / 4) 0; + white-space: nowrap; + overflow-x: auto; + overflow-y: hidden; } + header.row { + box-sizing: content-box; } + header .logo { + color: var(--header-fore-color); + font-size: 1.75rem; + padding: var(--universal-padding) calc(2 * var(--universal-padding)); + text-decoration: none; } + header button, header [type="button"], header .button, header [role="button"] { + box-sizing: border-box; + position: relative; + top: calc(0rem - var(--universal-padding) / 4); + height: calc(3.1875rem + var(--universal-padding) / 2); + background: var(--header-back-color); + line-height: calc(3.1875rem - var(--universal-padding) * 1.5); + text-align: center; + color: var(--header-fore-color); + border: 0; + border-radius: 0; + margin: 0; + text-transform: uppercase; } + header button:hover, header button:focus, header [type="button"]:hover, header [type="button"]:focus, header .button:hover, header .button:focus, header [role="button"]:hover, header [role="button"]:focus { + background: var(--header-hover-back-color); } + +nav { + background: var(--nav-back-color); + color: var(--nav-fore-color); + border: 0.0625rem solid var(--nav-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); } + nav * { + padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); } + nav a, nav a:visited { + display: block; + color: var(--nav-link-color); + border-radius: var(--universal-border-radius); + transition: background 0.3s; } + nav a:hover, nav a:focus, nav a:visited:hover, nav a:visited:focus { + text-decoration: none; + background: var(--nav-hover-back-color); } + nav .sublink-1 { + position: relative; + margin-left: calc(2 * var(--universal-padding)); } + nav .sublink-1:before { + position: absolute; + left: calc(var(--universal-padding) - 1 * var(--universal-padding)); + top: -0.0625rem; + content: ''; + height: 100%; + border: 0.0625rem solid var(--nav-border-color); + border-left: 0; } + nav .sublink-2 { + position: relative; + margin-left: calc(4 * var(--universal-padding)); } + nav .sublink-2:before { + position: absolute; + left: calc(var(--universal-padding) - 3 * var(--universal-padding)); + top: -0.0625rem; + content: ''; + height: 100%; + border: 0.0625rem solid var(--nav-border-color); + border-left: 0; } + +footer { + background: var(--footer-back-color); + color: var(--footer-fore-color); + border-top: 0.0625rem solid var(--footer-border-color); + padding: calc(2 * var(--universal-padding)) var(--universal-padding); + font-size: 0.875rem; } + footer a, footer a:visited { + color: var(--footer-link-color); } + +header.sticky { + position: -webkit-sticky; + position: sticky; + z-index: 1101; + top: 0; } + +footer.sticky { + position: -webkit-sticky; + position: sticky; + z-index: 1101; + bottom: 0; } + +.drawer-toggle:before { + display: inline-block; + position: relative; + vertical-align: bottom; + content: '\00a0\2261\00a0'; + font-family: sans-serif; + font-size: 1.5em; } +@media screen and (min-width: 500px) { + .drawer-toggle:not(.persistent) { + display: none; } } + +[type="checkbox"].drawer { + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); } + [type="checkbox"].drawer + * { + display: block; + box-sizing: border-box; + position: fixed; + top: 0; + width: 320px; + height: 100vh; + overflow-y: auto; + background: var(--drawer-back-color); + border: 0.0625rem solid var(--drawer-border-color); + border-radius: 0; + margin: 0; + z-index: 1110; + right: -320px; + transition: right 0.3s; } + [type="checkbox"].drawer + * .drawer-close { + position: absolute; + top: var(--universal-margin); + right: var(--universal-margin); + z-index: 1111; + width: 2rem; + height: 2rem; + border-radius: var(--universal-border-radius); + padding: var(--universal-padding); + margin: 0; + cursor: pointer; + transition: background 0.3s; } + [type="checkbox"].drawer + * .drawer-close:before { + display: block; + content: '\00D7'; + color: var(--drawer-close-color); + position: relative; + font-family: sans-serif; + font-size: 2rem; + line-height: 1; + text-align: center; } + [type="checkbox"].drawer + * .drawer-close:hover, [type="checkbox"].drawer + * .drawer-close:focus { + background: var(--drawer-hover-back-color); } + @media screen and (max-width: 320px) { + [type="checkbox"].drawer + * { + width: 100%; } } + [type="checkbox"].drawer:checked + * { + right: 0; } + @media screen and (min-width: 500px) { + [type="checkbox"].drawer:not(.persistent) + * { + position: static; + height: 100%; + z-index: 1100; } + [type="checkbox"].drawer:not(.persistent) + * .drawer-close { + display: none; } } + +/* + Definitions for the responsive table component. +*/ +/* Table module CSS variable definitions. */ +:root { + --table-border-color: #aaa; + --table-border-separator-color: #666; + --table-head-back-color: #e6e6e6; + --table-head-fore-color: #111; + --table-body-back-color: #f8f8f8; + --table-body-fore-color: #111; + --table-body-alt-back-color: #eee; } + +table { + border-collapse: separate; + border-spacing: 0; + : margin: calc(1.5 * var(--universal-margin)) var(--universal-margin); + display: flex; + flex: 0 1 auto; + flex-flow: row wrap; + padding: var(--universal-padding); + padding-top: 0; + margin: calc(1.5 * var(--universal-margin)) var(--universal-margin); } + table caption { + font-size: 1.25 * rem; + margin: calc(2 * var(--universal-margin)) 0; + max-width: 100%; + flex: 0 0 100%; + text-align: left;} + table thead, table tbody { + display: flex; + flex-flow: row wrap; + border: 0.0625rem solid var(--table-border-color); } + table thead { + z-index: 999; + border-radius: var(--universal-border-radius) var(--universal-border-radius) 0 0; + border-bottom: 0.0625rem solid var(--table-border-separator-color); } + table tbody { + border-top: 0; + margin-top: calc(0 - var(--universal-margin)); + border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); } + table tr { + display: flex; + padding: 0; } + table th, table td { + padding: calc(0.5 * var(--universal-padding)); + font-size: 0.9rem; } + table th { + text-align: left; + background: var(--table-head-back-color); + color: var(--table-head-fore-color); } + table td { + background: var(--table-body-back-color); + color: var(--table-body-fore-color); + border-top: 0.0625rem solid var(--table-border-color); } + +table:not(.horizontal) { + overflow: auto; + max-height: 850px; } + table:not(.horizontal) thead, table:not(.horizontal) tbody { + max-width: 100%; + flex: 0 0 100%; } + table:not(.horizontal) tr { + flex-flow: row wrap; + flex: 0 0 100%; } + table:not(.horizontal) th, table:not(.horizontal) td { + flex: 1 0 0%; + overflow: hidden; + text-overflow: ellipsis; } + table:not(.horizontal) thead { + position: sticky; + top: 0; } + table:not(.horizontal) tbody tr:first-child td { + border-top: 0; } + +table.horizontal { + border: 0; } + table.horizontal thead, table.horizontal tbody { + border: 0; + flex-flow: row nowrap; } + table.horizontal tbody { + overflow: auto; + justify-content: space-between; + flex: 1 0 0; + margin-left: calc( 4 * var(--universal-margin)); + padding-bottom: calc(var(--universal-padding) / 4); } + table.horizontal tr { + flex-direction: column; + flex: 1 0 auto; } + table.horizontal th, table.horizontal td { + width: 100%; + border: 0; + border-bottom: 0.0625rem solid var(--table-border-color); } + table.horizontal th:not(:first-child), table.horizontal td:not(:first-child) { + border-top: 0; } + table.horizontal th { + text-align: right; + border-left: 0.0625rem solid var(--table-border-color); + border-right: 0.0625rem solid var(--table-border-separator-color); } + table.horizontal thead tr:first-child { + padding-left: 0; } + table.horizontal th:first-child, table.horizontal td:first-child { + border-top: 0.0625rem solid var(--table-border-color); } + table.horizontal tbody tr:last-child td { + border-right: 0.0625rem solid var(--table-border-color); } + table.horizontal tbody tr:last-child td:first-child { + border-top-right-radius: 0.25rem; } + table.horizontal tbody tr:last-child td:last-child { + border-bottom-right-radius: 0.25rem; } + table.horizontal thead tr:first-child th:first-child { + border-top-left-radius: 0.25rem; } + table.horizontal thead tr:first-child th:last-child { + border-bottom-left-radius: 0.25rem; } + +@media screen and (max-width: 499px) { + table, table.horizontal { + border-collapse: collapse; + border: 0; + width: 100%; + display: table; } + table thead, table th, table.horizontal thead, table.horizontal th { + border: 0; + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); } + table tbody, table.horizontal tbody { + border: 0; + display: table-row-group; } + table tr, table.horizontal tr { + display: block; + border: 0.0625rem solid var(--table-border-color); + border-radius: var(--universal-border-radius); + background: #fafafa; + padding: var(--universal-padding); + margin: var(--universal-margin); + margin-bottom: calc(2 * var(--universal-margin)); } + table th, table td, table.horizontal th, table.horizontal td { + width: auto; } + table td, table.horizontal td { + display: block; + border: 0; + text-align: right; } + table td:before, table.horizontal td:before { + content: attr(data-label); + float: left; + font-weight: 600; } + table th:first-child, table td:first-child, table.horizontal th:first-child, table.horizontal td:first-child { + border-top: 0; } + table tbody tr:last-child td, table.horizontal tbody tr:last-child td { + border-right: 0; } } +:root { + --table-body-alt-back-color: #eee; } + +table tr:nth-of-type(2n) > td { + background: var(--table-body-alt-back-color); } + +@media screen and (max-width: 500px) { + table tr:nth-of-type(2n) { + background: var(--table-body-alt-back-color); } } +:root { + --table-body-hover-back-color: #90caf9; } + +table.hoverable tr:hover, table.hoverable tr:hover > td, table.hoverable tr:focus, table.hoverable tr:focus > td { + background: var(--table-body-hover-back-color); } + +@media screen and (max-width: 500px) { + table.hoverable tr:hover, table.hoverable tr:hover > td, table.hoverable tr:focus, table.hoverable tr:focus > td { + background: var(--table-body-hover-back-color); } } +/* + Definitions for contextual background elements, toasts and tooltips. +*/ +/* Contextual module CSS variable definitions */ +:root { + --mark-back-color: #0277bd; + --mark-fore-color: #fafafa; } + +mark { + background: var(--mark-back-color); + color: var(--mark-fore-color); + font-size: 0.95em; + line-height: 1em; + border-radius: var(--universal-border-radius); + padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); } + mark.inline-block { + display: inline-block; + font-size: 1em; + line-height: 1.5; + padding: calc(var(--universal-padding) / 2) var(--universal-padding); } + +:root { + --toast-back-color: #424242; + --toast-fore-color: #fafafa; } + +.toast { + position: fixed; + bottom: calc(var(--universal-margin) * 3); + left: 50%; + transform: translate(-50%, -50%); + z-index: 1111; + color: var(--toast-fore-color); + background: var(--toast-back-color); + border-radius: calc(var(--universal-border-radius) * 16); + padding: var(--universal-padding) calc(var(--universal-padding) * 3); } + +:root { + --tooltip-back-color: #212121; + --tooltip-fore-color: #fafafa; } + +.tooltip { + position: relative; + display: inline-block; } + .tooltip:before, .tooltip:after { + position: absolute; + opacity: 0; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + transition: all 0.3s; + z-index: 1010; + left: 50%; } + .tooltip:not(.bottom):before, .tooltip:not(.bottom):after { + bottom: 75%; } + .tooltip.bottom:before, .tooltip.bottom:after { + top: 75%; } + .tooltip:hover:before, .tooltip:hover:after, .tooltip:focus:before, .tooltip:focus:after { + opacity: 1; + clip: auto; + -webkit-clip-path: inset(0%); + clip-path: inset(0%); } + .tooltip:before { + content: ''; + background: transparent; + border: var(--universal-margin) solid transparent; + left: calc(50% - var(--universal-margin)); } + .tooltip:not(.bottom):before { + border-top-color: #212121; } + .tooltip.bottom:before { + border-bottom-color: #212121; } + .tooltip:after { + content: attr(aria-label); + color: var(--tooltip-fore-color); + background: var(--tooltip-back-color); + border-radius: var(--universal-border-radius); + padding: var(--universal-padding); + white-space: nowrap; + transform: translateX(-50%); } + .tooltip:not(.bottom):after { + margin-bottom: calc(2 * var(--universal-margin)); } + .tooltip.bottom:after { + margin-top: calc(2 * var(--universal-margin)); } + +:root { + --modal-overlay-color: rgba(0, 0, 0, 0.45); + --modal-close-color: #444; + --modal-close-hover-color: #f0f0f0; } + +[type="checkbox"].modal { + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); } + [type="checkbox"].modal + div { + position: fixed; + top: 0; + left: 0; + display: none; + width: 100vw; + height: 100vh; + background: var(--modal-overlay-color); } + [type="checkbox"].modal + div .card { + margin: 0 auto; + max-height: 50vh; + overflow: auto; } + [type="checkbox"].modal + div .card .modal-close { + position: absolute; + top: 0; + right: 0; + width: 1.75rem; + height: 1.75rem; + border-radius: var(--universal-border-radius); + padding: var(--universal-padding); + margin: 0; + cursor: pointer; + transition: background 0.3s; } + [type="checkbox"].modal + div .card .modal-close:before { + display: block; + content: '\00D7'; + color: var(--modal-close-color); + position: relative; + font-family: sans-serif; + font-size: 1.75rem; + line-height: 1; + text-align: center; } + [type="checkbox"].modal + div .card .modal-close:hover, [type="checkbox"].modal + div .card .modal-close:focus { + background: var(--modal-close-hover-color); } + [type="checkbox"].modal:checked + div { + display: flex; + flex: 0 1 auto; + z-index: 1200; } + [type="checkbox"].modal:checked + div .card .modal-close { + z-index: 1211; } + +:root { + --collapse-label-back-color: #e8e8e8; + --collapse-label-fore-color: #212121; + --collapse-label-hover-back-color: #f0f0f0; + --collapse-selected-label-back-color: #ececec; + --collapse-border-color: #ddd; + --collapse-content-back-color: #fafafa; + --collapse-selected-label-border-color: #0277bd; } + +.collapse { + width: calc(100% - 2 * var(--universal-margin)); + opacity: 1; + display: flex; + flex-direction: column; + margin: var(--universal-margin); + border-radius: var(--universal-border-radius); } + .collapse > [type="radio"], .collapse > [type="checkbox"] { + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); } + .collapse > label { + flex-grow: 1; + display: inline-block; + height: 1.5rem; + cursor: pointer; + transition: background 0.3s; + color: var(--collapse-label-fore-color); + background: var(--collapse-label-back-color); + border: 0.0625rem solid var(--collapse-border-color); + padding: calc(1.5 * var(--universal-padding)); } + .collapse > label:hover, .collapse > label:focus { + background: var(--collapse-label-hover-back-color); } + .collapse > label + div { + flex-basis: auto; + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + transition: max-height 0.3s; + max-height: 1px; } + .collapse > :checked + label { + background: var(--collapse-selected-label-back-color); + border-bottom-color: var(--collapse-selected-label-border-color); } + .collapse > :checked + label + div { + box-sizing: border-box; + position: relative; + width: 100%; + height: auto; + overflow: auto; + margin: 0; + background: var(--collapse-content-back-color); + border: 0.0625rem solid var(--collapse-border-color); + border-top: 0; + padding: var(--universal-padding); + clip: auto; + -webkit-clip-path: inset(0%); + clip-path: inset(0%); + max-height: 850px; } + .collapse > label:not(:first-of-type) { + border-top: 0; } + .collapse > label:first-of-type { + border-radius: var(--universal-border-radius) var(--universal-border-radius) 0 0; } + .collapse > label:last-of-type:not(:first-of-type) { + border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); } + .collapse > label:last-of-type:first-of-type { + border-radius: var(--universal-border-radius); } + .collapse > :checked:last-of-type:not(:first-of-type) + label { + border-radius: 0; } + .collapse > :checked:last-of-type + label + div { + border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); } + +/* + Custom elements for contextual background elements, toasts and tooltips. +*/ +mark.secondary { + --mark-back-color: #d32f2f; } + +mark.tertiary { + --mark-back-color: #308732; } + +mark.tag { + padding: calc(var(--universal-padding)/2) var(--universal-padding); + border-radius: 1em; } + +/* + Definitions for progress elements and spinners. +*/ +/* Progess module CSS variable definitions */ +:root { + --progress-back-color: #ddd; + --progress-fore-color: #555; } + +progress { + display: block; + vertical-align: baseline; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + height: 0.75rem; + width: calc(100% - 2 * var(--universal-margin)); + margin: var(--universal-margin); + border: 0; + border-radius: calc(2 * var(--universal-border-radius)); + background: var(--progress-back-color); + color: var(--progress-fore-color); } + progress::-webkit-progress-value { + background: var(--progress-fore-color); + border-top-left-radius: calc(2 * var(--universal-border-radius)); + border-bottom-left-radius: calc(2 * var(--universal-border-radius)); } + progress::-webkit-progress-bar { + background: var(--progress-back-color); } + progress::-moz-progress-bar { + background: var(--progress-fore-color); + border-top-left-radius: calc(2 * var(--universal-border-radius)); + border-bottom-left-radius: calc(2 * var(--universal-border-radius)); } + progress[value="1000"]::-webkit-progress-value { + border-radius: calc(2 * var(--universal-border-radius)); } + progress[value="1000"]::-moz-progress-bar { + border-radius: calc(2 * var(--universal-border-radius)); } + progress.inline { + display: inline-block; + vertical-align: middle; + width: 60%; } + +:root { + --spinner-back-color: #ddd; + --spinner-fore-color: #555; } + +@keyframes spinner-donut-anim { + 0% { + transform: rotate(0deg); } + 100% { + transform: rotate(360deg); } } +.spinner { + display: inline-block; + margin: var(--universal-margin); + border: 0.25rem solid var(--spinner-back-color); + border-left: 0.25rem solid var(--spinner-fore-color); + border-radius: 50%; + width: 1.25rem; + height: 1.25rem; + animation: spinner-donut-anim 1.2s linear infinite; } + +/* + Custom elements for progress bars and spinners. +*/ +progress.primary { + --progress-fore-color: #1976d2; } + +progress.secondary { + --progress-fore-color: #d32f2f; } + +progress.tertiary { + --progress-fore-color: #308732; } + +.spinner.primary { + --spinner-fore-color: #1976d2; } + +.spinner.secondary { + --spinner-fore-color: #d32f2f; } + +.spinner.tertiary { + --spinner-fore-color: #308732; } + +/* + Definitions for icons - powered by Feather (https://feathericons.com/). +*/ +span[class^='icon-'] { + display: inline-block; + height: 1em; + width: 1em; + vertical-align: -0.125em; + background-size: contain; + margin: 0 calc(var(--universal-margin) / 4); } + span[class^='icon-'].secondary { + -webkit-filter: invert(25%); + filter: invert(25%); } + span[class^='icon-'].inverse { + -webkit-filter: invert(100%); + filter: invert(100%); } + +span.icon-alert { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12' y2='16'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-bookmark { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-calendar { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-credit { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='1' y='4' width='22' height='16' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='1' y1='10' x2='23' y2='10'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-edit { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 14.66V20a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5.34'%3E%3C/path%3E%3Cpolygon points='18 2 22 6 12 16 8 16 8 12 18 2'%3E%3C/polygon%3E%3C/svg%3E"); } +span.icon-link { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'%3E%3C/path%3E%3Cpolyline points='15 3 21 3 21 9'%3E%3C/polyline%3E%3Cline x1='10' y1='14' x2='21' y2='3'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-help { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3'%3E%3C/path%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='17' x2='12' y2='17'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-home { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z'%3E%3C/path%3E%3Cpolyline points='9 22 9 12 15 12 15 22'%3E%3C/polyline%3E%3C/svg%3E"); } +span.icon-info { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='16' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='8' x2='12' y2='8'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-lock { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='11' width='18' height='11' rx='2' ry='2'%3E%3C/rect%3E%3Cpath d='M7 11V7a5 5 0 0 1 10 0v4'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-mail { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z'%3E%3C/path%3E%3Cpolyline points='22,6 12,13 2,6'%3E%3C/polyline%3E%3C/svg%3E"); } +span.icon-location { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z'%3E%3C/path%3E%3Ccircle cx='12' cy='10' r='3'%3E%3C/circle%3E%3C/svg%3E"); } +span.icon-phone { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-rss { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 11a9 9 0 0 1 9 9'%3E%3C/path%3E%3Cpath d='M4 4a16 16 0 0 1 16 16'%3E%3C/path%3E%3Ccircle cx='5' cy='19' r='1'%3E%3C/circle%3E%3C/svg%3E"); } +span.icon-search { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-settings { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='3'%3E%3C/circle%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-share { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='18' cy='5' r='3'%3E%3C/circle%3E%3Ccircle cx='6' cy='12' r='3'%3E%3C/circle%3E%3Ccircle cx='18' cy='19' r='3'%3E%3C/circle%3E%3Cline x1='8.59' y1='13.51' x2='15.42' y2='17.49'%3E%3C/line%3E%3Cline x1='15.41' y1='6.51' x2='8.59' y2='10.49'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-cart { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='21' r='1'%3E%3C/circle%3E%3Ccircle cx='20' cy='21' r='1'%3E%3C/circle%3E%3Cpath d='M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-upload { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'%3E%3C/path%3E%3Cpolyline points='17 8 12 3 7 8'%3E%3C/polyline%3E%3Cline x1='12' y1='3' x2='12' y2='15'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-user { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='12' cy='7' r='4'%3E%3C/circle%3E%3C/svg%3E"); } + +/* + Definitions for utilities and helper classes. +*/ +/* Utility module CSS variable definitions */ +:root { + --generic-border-color: rgba(0, 0, 0, 0.3); + --generic-box-shadow: 0 0.25rem 0.25rem 0 rgba(0, 0, 0, 0.125), 0 0.125rem 0.125rem -0.125rem rgba(0, 0, 0, 0.25); } + +.hidden { + display: none !important; } + +.visually-hidden { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; } + +.bordered { + border: 0.0625rem solid var(--generic-border-color) !important; } + +.rounded { + border-radius: var(--universal-border-radius) !important; } + +.circular { + border-radius: 50% !important; } + +.shadowed { + box-shadow: var(--generic-box-shadow) !important; } + +.responsive-margin { + margin: calc(var(--universal-margin) / 4) !important; } + @media screen and (min-width: 500px) { + .responsive-margin { + margin: calc(var(--universal-margin) / 2) !important; } } + @media screen and (min-width: 1280px) { + .responsive-margin { + margin: var(--universal-margin) !important; } } + +.responsive-padding { + padding: calc(var(--universal-padding) / 4) !important; } + @media screen and (min-width: 500px) { + .responsive-padding { + padding: calc(var(--universal-padding) / 2) !important; } } + @media screen and (min-width: 1280px) { + .responsive-padding { + padding: var(--universal-padding) !important; } } + +@media screen and (max-width: 499px) { + .hidden-sm { + display: none !important; } } +@media screen and (min-width: 500px) and (max-width: 1279px) { + .hidden-md { + display: none !important; } } +@media screen and (min-width: 1280px) { + .hidden-lg { + display: none !important; } } +@media screen and (max-width: 499px) { + .visually-hidden-sm { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; } } +@media screen and (min-width: 500px) and (max-width: 1279px) { + .visually-hidden-md { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; } } +@media screen and (min-width: 1280px) { + .visually-hidden-lg { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; } } + +/*# sourceMappingURL=mini-default.css.map */ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/_htmresc/st_logo.png b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/_htmresc/st_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8b80057fd3a454a97de1c9d732b7fede82c83227 GIT binary patch literal 18616 zcmbTd^-~<*6D~X~?jgaQV8LAj0X_tm1Ydk1xVy{Z3GPmS;IP2r4oh%%cMl#Qcz~Pl zz5l>lZ`GVRHB&V|boY7A^z(F|Z=Y4=aIwg-006*MkpHOuZ?5<^0x;12-SsK9!v0Mt zmQpHG08kT${nrHb-!rC@ysj$%ki7ceKq56ESOEZeJ%x`_nqEey{^(v>eK${gL>pJ% zX8+KBAR_W-jhDrs{egi|sP<73DP`UFoa(>xj;8qknEx2bL~2@t%3k>}hnl@CWQrW@ zqfK>@e3$sL-m%ftg0YAkk!@=P!Ognuz(zhb|Tux{FeX<<7(5oLVU8=W*sUZ*$TqlSb6o1O0a zzeP#ZW!;?#>0N5v?0D|q?mzD8-<^@1V0FH{fY}2A9ooXbylcB6Y>PVo4nMxLi|AWA z8M(b#9`j|%0v7ktATOSzsh-T7%Wqa>t*x!29M*iDetE6#^`?iEoQW5F*w7rjcWYw>-UyKyDHetK@Im)qdu0o-zudq@gQN3)r z=(%XIh|%7(Y}2mODA6--)=u;7mi|lUCki50L@QOyZN@2N`Bwwn9et)BF?yQr9`Sn# ze!a;09%cuNiCJ+Hwx|5Sw&L`0rJvq<$7D5j#Y=O^YcW)1x!+MVRWRVHrXDj~g@40Q zBvp_niE6-dasJKX&t@%;X`7_R9QhT$w_Dv~zW73kCM;9WC z#^@^R#^^HZ#`rQ5ZjC*^uYUMgw=ae5*IV2JyEL@LlJ1k!yA8p=fmyQ={`Pjq&sK}Y>k9r>*Y-3njDRLc8z*D?su--n+y(fpV8FB zwS%vLw=L>F9>rMJzXaXgg5NRvaHPKO=qdV`%ecKE^q=CNs6^=Vl)5QG9h0>AKM-1F zvU-S)!Vnz~yg}XNmnaKSqm&}<1}#nOBCWZsLvn3_pkm8Z)~*KF8yv=yRk*!4rf$7T zT*ey^g`%>`O82HoVNPMCaM^5e_Eeop`^`Wsro=Q9SzJ-{LW5j1QdRH>Oq5bEX({TJ-TNGPvNBrk5{my=8FEQ%0fftv4 z)$FK)-usf%cyd|Y@=r@u!~HI3-5_Q=E%R!AkEqtv$Yv%Zit4K`i*n5tM!wdwLFM?% z@N0D&tLS9%TD>`41R~`%HzXtZS6pjo$}fsAA6cq`&Llq^TE@#ID4eU}(xZH$-0oa>g$RMe)N_S(=w@nXEL&?{|e zd%-=H@Ei^9kz3up?3!?QYr2O7^M9)q_E2E@^vESGQ&5WzDh<(QgQEd3BICrRm8O)S!fPO#z(h0}Vk) zolMw(Ecl!UD7xMUH0>?+9qzTMCMQxcM+Od*!L7F!tiwSSG>D@|J~*c~gu?`RewztA z1cO8*h9GGR{``zPp9t6vZJ81Ar<-bz38Jv-ro`wI#Mq&-k$*5tL<>Pk=)T1H_z8YhPJDWCuq5c#f&iDRo3$~XHhc-#T3{whJvB?;N^IKpX^H#=oYNa@u&^9He20t za7qlYKRH^S(Tj2{XC=lPI|MVMOVVX4V8cbx(9Ix%YK__iyN9E(k)118*aO-OzZNT# zbhE^f=Cze>bdhX>8xBFW70+=Tb@QnIyKKmQGt`}ZHXrVVWgxIT1k&eFDonM5iFh{^ z;FtT_qYo%x6$`ChDD~;i`c>h@T~X~pZ&-v==wrV4)ra@?=39Z}7c)OR&&9#@9uxU( z?hh)jyY_o}tH;1B>v%95XoGM@gDYB{I@;aJAn;N$2z~uDX|IL`uf-*Mm1ic21|E8c zQZWw`gvb==bz|iv=774j$zii$vlW@T4LDFEfea$Z+frqVA{<)qP_mhp2AbFqEE(0z zfCJgi{n&vKxpSY#-W)(E-Y3u@1KQGcnWN=qz;Nz2-6>bIL8wZk?oy8xe49zo9Evpm zI>QVA&&4C5*aCjxksX%9lfPpQNw|#TzMQ;YvC%Rx=uA#dmU{e@tzaW&rq}9N5VXBw z6Mff^1He^5U}j4TZD};Z7u2!LZ@OjGIPgR|MLZ*9%)E@0nE%K=W5s+NOT~n_{fBc9 z8DlU6un9om`MN~!FtpPXkJSq(+KPHqF&N23_vGeqphc*cEAF=okHGoFWHHWTm&R zAZXR)=q}Jv`jsvKCoL27h?ylNq0fz5xasR{P`5RW_7kzL^b_#T@e?r5nGKuMX?!lz zcEq|hYJscWj{YtO1of8Xi0jH z6s+!rS0;ag(Cml~|NKB+tNwwq9kl+8wc0!T$L$CFw95drNPiuZ3jOf4G_NXoM$sQj zZn*2v3^ISC(OoqO%W>m};%SHDOcD)D7%f&?jnrI9&1_u;6m(x2g#=wb zH$Cl!I6f#QI6iFo2i^nPy^8_Rt0g@Gzv3FoK629)r#wPie#!P^T*B)9JDi>Qta-Ee zyLS}t0#vL+3WcNfUo47o=g+h7Q(waq$0Fo`#^t+!ugP{n=lV`j6a9^vBl)I!L&VaI zK(10FWw?KM*=_ynJ3HIwyD^##=aKUk4u|yIYk$&C>^B?x{I5c+Il`m3RQ%_=Tq`!D zQw3HQ7dw%VR~rkqeqr+THi``YT){njI8j~%3VNWBl3EUyQ zx>y&BaDTkwjg$12&1?kD`IcCB_?j~8XMfHm4iQ(TCj7-)DOn-+%UzP)ab?nnNlfTA zh(FmGsK1tl`G8>eb=1j~9lDZPh<*?zhjW@Gx5%UjcH4 zbrrd<#%%JyFrW`_Loz= zP30^V%kIB;=&%K@{YbXT6@(|c>dXlNk~?15SVEmMX6`Mjv>+MN2M$^N?ju|1T-qoW zJQV;x5rIpTc>eCM*`;fq^U3U2uW>l1RVxe^4B$CEub2J}+bN)$=(gE92((ah@ar_) z+I|k<9;iL6@Dyhc+LX|pTR>r3{P!==s^guY!a#cZ5Ry6QtTzvk zUh~+ICB=TnC(!+~G1}X`=zKbJF=VNy60Le=gO@j5lEJet5>jc!PbM+D!ZlS$KuYx&pkm{S?k)BU1<65@ z({=ySGqzCiV-vc5qOJ z48y)rR(Ys{uWIjyQX*o`4?xK$K9nE1K!t$coI~(ku$IzWaVM`ocnY1)=&_o_R%I_2 zZ_{Cs>@7#7ktZS)0EENs++_HHh39c*#7z#Pyifk3+e!lsET`nm%a#Zp{hflp4Vw$+ zOju*)#0tN99xzE1;G}_c;Oj@<_%Z8;SCB3P74uOYE__wpp<3HB0g0wsxZ1toEwg)5 z23F}NQwRV%3UQi)GQQt^$a%zzV8w>aIl;CkQ!6h%=n!jXPZ;sfULBWNTi1QT%V~R| zdrjBQt+%&EcrjOO0&pO(SR|R1%nis?Q}KUl75Q=`bI5TGenEMls+QNXGp;Grr-EZVy`f(ovFSmI(u6D90n zU}rWOG+9F)ioe9yO)lx~AD<~|_xP=uVs4I z6w+kccIU+(Ltf0bDM$mvJrBdPzjnQ4w#L-qTZ+S6V5l=pqj|%(!m@K!R(Sm5G<;5V zXK~r#d34;M-;>*+VXbyWbw`4vdOanA^uK`Ag&w)G;7}_OpATxWe^GjFe%&*Ocx)w7 zwt4Bs4luF3C-9V+n~E!?(W3d6$CtEn7OZ{~I`6iW|1x;QzkF49GF&d=Wg#fC2^Vn?KLfW@n~pFc4gBpg!U$uFR0 z6`f||PCJat3glNlwW|z^j;^p%9oQc82S&N+!L>xWR*UT~JbFCj)0}2J6c-rV3iVO! z`IdFp zB0H{SvHRu;zx(EM(0%j9fA`HVZ|@5Oo0EGok@w*1K*{Sg3QERYynQ|7kzI{t_?~>T zQGQ|?TPR(EZYAFen;>d7>k zc`O4jwao>J?dp~fG@8l|SBHzOE5h7?Ba_OYs%93|;KP${8}j%VGb?LRi<;yffk06& zmc)TH`g@-+zt@fG!z|MO3057>Y}ppB{w8IS2o68)NnHSA-jKa+X$k+&Klw{5Ksly#ye_HBKV&h1zbIsIT-|0XRq)zWf_~s9{=n3BOfpPy7{f5RZzL^9tdzjj zr)R?-SV}4UX;&dWNKq={6q|g;FEbIjXC}?$K%uY_ur_MF+MkJ>-c@8l1|6F7^BR4N zf%t(1oJ!m zg^z<^ddW{6+A~!=F*1he)s`5=HR&3O@tjq)pn!{ zodn}X=d$=iUh-ibxQ>PQw|#fHTLppRwXG}*HyUkLKB?Vxf>#@2_z&V#B0Cjvmfka$ znI~k?Pp)A)OXy(kdOeH7nbmp9bNb|>|e%T7Dg>BKo&y=JzU)v zs{+P#O$)wko3MOQY!bv_78@Q%uABK!ZPIi<~iCxyQ>J*D53j_;0vks;+?UxqO^ z8)9k;>&t3F)oFofc_t(0cdCn(OIM;4fePgKSw+PKcigoQR9JV_C-y`&%By+|aMjTd z;$iN6>#`KNXtG+yNhfl+PYn(#cr;Nf>DZ1mRU`A-PFI}Scq~0EgRR31c4LZcz_w!3 zU&-x*oGPQoz`-m#bYEC;V<7tHiC(wn395M}YNU9p|6@2$$6(9N_DyMjuOwT6X&Cu> zXg1{_^+%NsBhDf;)3V~J5%bl|^XVjqRgu^moR2288%NOgcLoNBkN6t5F&l2`tPvao zfAbQy!&*Ln*uWc{tVDqwT1{Q>{s19S6+;c@2e$2eZd>zL~I~M}G^8w4Y2bnyq)>=S+L6j%|@%XWqbYm%+}R z%Jg=|X7Y&0*lujN6>tzy)?{CBuT|FT#I=sU+569+)8oyIH?8?{Y{Im(PMHAGs5_GI z>1wLl+yiE$+I28-c2!jx)_?k2nIm}7iH=O{X#yL$s@}hUPf^xece9Vi{DUPRKm%@= zI4q=C$Qla?I0{;1W!^-Bt)o=r>#KNZnZPW3piq_&q`~HLF~1_^MHlt66*62}BJqzu zM;g!LlycVJ?1ohPMvFHu3^-`<`sR(iyLG`EB|;bk%3GG!#?x`m5gx zWnZm7bb@UTrR9OXVs1t)?(5a%Yqq>?ivrob2S7W|CH$C|Kscw z=5hgFRsHTTA{lDQ(a0VW8vk$By+wL4Ao<5{Br)oU$x2pMfJKrlPqr@4P$Y9Nt_7R| zCx>hhMeHtjM0mJ|?T<(EIY{^^cAiA&R=2C=g&o@6vm!E&&86BrLOf18fr==x77OBH zdyOvB1fjqxDMa5;G9@=qu?tN_vB?)=#H^qB;g*jHrr^*ISGt+pLXyWcu+bAWNk&IG zl?zGxV&+)tmQ@d~T5Yypa4*^P5t*t6C($W-Y9zknsGLXPPDR^RF~`>QcV4iB%ltJg#%JgzSOl!L!d<7;Gfa5FAv zjVdBTD(TpZ3>zF8@VbIAM{aYtDv8fh>oAmOoV`*>G_abe#aOPM+6b%!IzPP2K{>A5U*>>2+^+79)a z;+jQ03qhGCNA7Yx7^lX9Ba9FuFHNen`s{buqNeEv)$x#QoePK6M~soRL17NVafu`4RB%F$`Pl z5~X9X{(zDkw(=x-=6pOllhfSrJCozywriAokKZ^VZ?epc?F2YfOmC=V98gW?oL=*# zC!4VJtdyAXwE6cHlNoijVy3KiZxeTrjL5AO4?|IT4#6gV63bUTC!(fd*MK@3^J@F! zOg&Y}^l`KyT>$RnH8O17_%?_PVh?o(+5L|_R7c|c+R_PRXb26L8QM&z+5MaH{wtOk zn}L=^TXs*WwrBLOJ6hDKim{LKAa3?WEiRefh;#TMZ3y1zA%QAUYh={Ux!GU!o~ zQNH$+pUp$BPoB27%q zF^6BflF{;t=SZSz+GrMJ3q~ti7gQ;5SbjS`5!DFxQB8KOt1OQ(G%_V;vcdj>K_dXjNxb}0M?HyjDs(afDCVx%>+I2GAO;jMfy0Iwh$=Utfm z5snMAm4|C3O1?MDEQ%I@RL1I{SrN67(Q)b*7k&Ip+-THJr%-;ILx=v!SaW75@EH3` zUhVOn4CYZ>iZ!iaGNBq9Be`Mcq5Opf?{HZfcJM-VDr$qSCy^3Lij|O&UW{&ffZ&!( zaA9$H9_5lFs;vRx6|mmn{Ic~u%y*(_t~*m12^>%iUOQ9Ap<@`U;!iRpBZ5y=p}@B6 zSP;R6QS{hs7)q75Mgj7814d~Bae=<{A1Z5>;LN66N?m?;5pl?`*_wW1l4a8IBb4tyR6@^@^BOm`{tD6YyAv};)Te2G+K}4;<~T9 ztiHbWTlGjD1=omQ_viT9PJOR7GjZ^{`7u?a_$hGpx54G9Z4Uj-NJ+>3SA0ZSx1vXw zLxYWusP2Sm*#o~_#B)vb&lTfmtsonTnPHIvx!#}HYvp=bPcZe zcHOCWuo0{MxR+#P#Pz1PSlaT$g-HbB!hTlHpV_F!Ay^U-vb1-6W)!xh?3imeOv*Z3 z=D=Ij-4e>!J=_Q#nqT5Fkomgv(@3uQo!?=8R9Sw(0)&ni z2jsV8*xm^OAO91C)$^*!X=%ZHvh_G35URQ9mZ|{A0)E?gJcL0T$H-NA92s6VF$CYW z9RHBse3R!V%B}9#+)P1_9L@j@2VcH-GZ=N2{$k05r?kj$KxpvthW zd7m|F4Ka%sEOHJC`oN z{Q9h2$S$VYkMHBEw7ybMx&7`nIaMLI5n~s)u5f7_tg^|2p4eFF&|6C45|-}T zY2bbCicJ7u0b>nvzMSvbBTOChoOAKvC$b5)Y}lT;{a-@oZBJ!oQNfsC36M4qtjvVR zX;Qkn$Pw56!sOMyw2f6>a4-#^ zy$1D*lt}-KofQ^atUig?;uYP;un=4nq7RPpS6+7^7eT`a+9Hs&(5Wu`IyLv0kJINP zH{2$kHb`Me^3C!975F7KG!qcJ%Ot-tp1f*bJffu1KR9B1lQ=XYBq15?hlJ33*QN-~ z25i$#OI}x{k+-P3EKo3v2XVk4?t;KE4nj1dk!Zo@w6D?!o#k^~T|3?;an*{_dc}rZ zWWWrKbdBu0k$7Zn5A%~0$lei$vU1P?CE&!L*!t%`ziuxu= z$+Xt=qUvFYn;a&JSK-D!mWnDWtF|5q!R|hT$Hv!*O-Hv$ zFMd5*W#~$3AJN-2|IVd@2bWN6TIfD_0uz(~vS50vn&4k2seimRF5`Q+1IS}!NNHN| zuWuQz50#5kO>f(wTSg+{VKXLrOZR$Gm~DhS1f%%-9{FGG$s*ZrqKZL|g5VaRU11N3WB;tGWJx5jj1rPZ1}$YE7~gsu zE25FmauDeN0tjmI!T8LA_@Jktp-r4gQRI3~pz@ext*^u56U%RNNACtB2^N&i&Zkq_ z`%gV|mr`$f?Rog-De|tRlA$9w&gIG-7Zqk}`K~S#ez0!r0TA4$*?1vW^S1eRHim+x~x!Fuo?ZZGGykdj`C(v!pIX!M7^#v%t*g zcznI+6jSi4g8knZOJ2XD^*-Nu8++1xNL67@Dpa}id>w3=oC<2l|TauHqSGbyr z9Lb=M3fe$ymZM2IcIy2$WhWPLfA8YEy!~$2XHICgk})!EbwTa@re-=DC1|8#7fNFq6gJ2K}GKAX`f_@q32jY5x4yTSxUH;`}j*L?c8b@JA9D(4X1n>r5 zmjA{5zUzqX9?77@2f4TGSC#Gv z>RXD%m8Sx#GLz`?10nyLA3f`rKtm)2mp8 z2WUMD#ZK*6rx@tHUO&Z&$15&*p$9S&RarVs7nI?jWCTx!i z0n`(39&^Y>ScN)8+_K-B#JBi}jEM2qqgbCqWKx*4*ll_rs)9n)b|4=f&23 zGJ5Ub{5j_`P?1;gHXtz{3VvNPjI4v63M z7VR-O|JQRM-E&ZagmZ6Y#+`oTU{Zdpg*T>rA?e2lXyimlx-MsB_vpS!^2jDQhm%@q z{n8XwoaYQc8y7Itb%2)$a=$~0tev`)%-s+AXZ8I@XV4DuPx#4Z3^R?1Q&1e*!{+@j zwy0-{m|^s)xqlSU>jQk{owo@5+inF)-p_24DlAw`pUe~G8ATB<-h>G97|FK_kfkQlN-!Xir7CB=dF)cJj`)++W>CeZ z0KpG5Ul%&-7q_N%mRtvtM37+jS>A#7p`RadxDFCIFsAEA)28 zRc#)^^3Z1>`W_P8_n+_5l5pGfayTk_=7^k}d#ir!c>8mR4k$J+> z7$;sN^3k#e1A<-CaO6F6V7^1u(puc4hVnfPK2u$wSE_XF>^Bp?OAv{2Y8)b{(a(2LFQfe!w)T1x>k{ZpuhTF(Y6rhpZbrH!ElxM! z5seXw{2(-vFEyNn8P2QzldxYgR;$=9Va+n>oR-HQXL;u7|E|m|OuX!t) z=Y4P{a-kdSJHXaCvpi=8=DW$Bomevgq&Ys4T71MX_~k_QpcOJ7j|>5e z8fKax8KCNY#00?1+;-F_`mYl6?wiA0M9-%AWH7g{~~uALu>r1q7;w|*!aJIeE{mR8WtR@KBhs8TcC2jA=CW|Xy-ycIi>d)c7Okmo?_;IS6kWJ z(`FLRj~hxiQw>hGi`}`RB+q+jpRWZ9z114q7dyj#>yMG?n=NfcSz}CGOi5Bt#D4u( zFREX`PCs3=cqxne=H=$udT;=|-YI7ij;hPlH)3oXm z`Zikh-OIS^*V9YKw;%r4iW?YA#ppM%LKP=jnMYQ)JEBqy1t4U@E<8VwMW2U*KvaS5 zNDwVyHjTg6hvcbS>{N7lJu=~^Ut)S#sq~v9%#hIV2H~>o^9=!kEGypac0E4e6TQIW zr~+Bn`Sb4k*0*Zts;f;Vq@fsZn1hLBQyIO8W(13u0211vHK)RMC5neH4xx7?6jMVOl3i-ENH1NU{ z-FW1hXwfmWi;TOg`k_dSL1ckNlukjE5IiKg=2DaEcWG#qTCd+ts`vavz;Wye>fPE6 zy5Y~H#6~R#r29XgZcKEUWF`#TkPjT0Tb$nr`$rM*rO!0=z{AwY-%*%Y>1iy07;xo= zlqRRR7Oc25bnNStf}IG@3`}b^k0oTD!zg(19YJjRnXs}9jracK>Fw6_hgpNk9M$d_ zY;%@p@*94vn6~^S;rS|c_SBN9%41Y5CNDz~xgJ>zs5bOlC^*0Hm`3d+UdEAQlhAJ~ z9rS!JpiEjf-g5TxWc*_}=Uu;kRBG#hg)R{HVt_KfnWZwXW)vK%qN^F`Uk1yRWlJX^%Xv zrk4pFBKoY0c4V8}-7;k5jeHn#no6bE=CpUiQ*YjAXr&^e4Ji=kd5l#`F`6lq$7V{v z3HxGM@4$C!_rCJ0-}}J#b+>i@#M5T@ zDq!my3QKfc?}%tQt*O2KZN233YvPN6nJ}^KNmAv>Z%4u&!~ecZRVXA}Vl6Juc1QC% z^+u0V1RbM%wwc6J;|v%G|8k{t}#XaV3b2aS>;{E0?a{QN?D zjap1}Foj*+4gOfLe03+j+-fGX6EVmh%q%{kCs18^=Y$ttM`Ru~Sih(@mxvo*(|OHJwq(zE2(ex%#gkzo*Y14gL&0 zb&R`Soa5K^wB%jo6cc>zQGL@J1IWOVy&G6nrZ5tClv8t|5cv^+Gb2^+T0kC3kdVb= zzt>d9Y8%qhJjVP{A;^*2E;@stxE=CCM8#hlN3jEzVQ}z~l*fFX-3jF?-%dnrKMp>* z+*ojsjy{>@Jvb5ZmHokSc4fmUNZRBEvkDd^(WV&AoGicLZM&xx+F?MzT8H=FtNK9| zS}XSejv}P(R*P5=IL)L^{d8bx{SC>9DDxXj4@z-n^Hya-p}k%LC>kvh2A}eK-{n8P z{ymeI^r5$}WuJ`hTT7y&m(wGugFoqC45jML$-|3L7JDo`mbG@4AeOa9^F5Xfc~AdJ z6z*HExRMYeE;qZsGE(eCPFCa$fMk$Uzn)5Lqpt$(K3(+J)whl&sJ0{&+hDO7rV zmH=Vx#~{t)BZI;GL9NP4eoCJAPi}V8s2_pM0^Qn!dLjeT+!j52$p%MSaS9-1=VIXE zZZI?CV3-Z~UNNk|?P_bEXiaFvcS$(=j(imNA_Txz*qk*3Zt> zNTsgN3vU6G(NEuWibkSSE-gZ&wr@}`tuvHEIJGFQY)vT7_Sn%Zf>;noCdR{II*9Uy zi1DPT!QZt9edc?XCO_%vF)Vha6tK-jiPV+wdZr2-8Z+moIE4fA9Um2wrmprd`ujDw zA4$!<#8*6C%(UP!wX!r@9XeCS{UX~rhBT6- z&m5@`REID~K)qRRLN40)>Fz=?P=C-jXZA1}lMo#Lic@|(zYtC?Sr$}gjz;wX-)dH; z>kQvsjFQ|FEvL5r4GE`Vi>HJ+qxMkQH`jx)M#C81t{fBmVaUEu2p_>}$^Lp*OiKYZg_C_ycw2+?0OT`)la$oyQwx zn_edD@HInp4-Gny;i{I~SnCp_RpFSS_!Eo_CI3DYHotlBCu`)~d17BV58M;K#oqAY zMpX+Xw9;xj#wpOozs(lT<+Th^5&14m(|Q*%;z`vKh4SNgAVBe}N~g2sLPrFC2|fE< zFpnnM-xp>{8@7DssTYKd@0S%KXilVkqrjiHGyiM<4X=4ToUoPe$O?bRyn$W!y*w+D z6&Dp2t9Ct*jrJO53Vv$UzniUP=-;pr=_NhmXKlFLRkmbSfW7QwHhvWb87Y|_ zx8ovSSXKm9h{zGnW$Hh-iI?ZMHSbjn*3Sh{-$#hX$;rQovTb9bL)q_$Wc zZmKiDhCM5p5vXSn($(MVPz`Tl^8Dq9O!MXzxdIh}Yi;I?zh>o(TXxwNlF}fbbJWC- z#GcWxTx796z)2UUjk&XWZFb3^oh-r)7Kkx{urkexT2D1!HLjPN~zvz2X#hz4#kSWLV*CW#DJu#do;exLU5E*Yb2H*HhXE&}5w)`L0O>xl{F?nRCT2 z*sv_q70&aZdR}eGSdA;#MccWyIlME%-v<$!Uv*^qnA&%(krwShZthK$iyit6H#l;> zK-^@!-w;mtEMfj7rnxx}?MKV=JHn^z-cHiGPN(d-mV0j(9hnwwg#l4%su_AWn&D=e zjR-cx9)55a@TwJcUi!8R@A2vD&T99g^diZcn-!n?8)u3269>8(cQRcMciiUGO^eip z5B)0E8kXbcz#sx*&|^TUl$Lb)lb&Ip>#TdtDfUcwzE~nzmuQ7EmTjAgdgUiGuSuNa zpCb6rE6(O5o(^pW-+RuE)g@nrZK=PFeQcL58r8o>9J$FQ<9+2A1d*DBdQ!b*dT;;4 z$Xo4EWN=S2^E$tAy9hSL=6Vn#bHD2g;0=sNhjJ6d)KUocZ)+A6o6_A*qTK}$*h#RS zyk#XkuOO@^1ht8v-%9N{Y9oewzu$e7L(scb^mXW2_TiW*-y)vNyH`OadIrI^Y>*Zd zp?=ROXFoq0Kk^tpwCFt$B)QKsZPM$&nJ*fs2;Xd)FtPd@FMUTnfVUp;sJHFaw;TuBTKR%BOW_}ClL_Bhz{A0l{Qgc%@tjIWj2ys8T z-56z(;=%E*LE!6!#2)6$>Eq4>1p;7`)Z_NSc1X=l%@0`gB7usIOR#p2{Cap%H#@u+ z`w+GL;VMer0DCjGMC|TGF_;&EgwZvSq=Q8@4}X7rF+n51h%CM@hl5WX$J z1a?I~km{+qh|RA-3+BNxgHjmg>KA!Bo!rA$QbB?cckI}KdkcLRox3JZd`fkXjx#A+ z_&En<1xc&Qmnoz0c*OV_guW?$J#uUHP(jS@beks0sZ#) z21ebzv6U?Wp@^S4Wn-$u_zmK3cE*C1Mlc5xAi|J_lu9>vY@H z+=VfBpk=&5g2V=pY;m2PHSN1`4hDAzs43VInEYm~-~S`AxRI%f?TU84wXtx z=s<1xk#OUIW)~ZG_2?E}ncAz?RlZ%Nu{wqJtc71aL~G>$Y^@Cl^I zh)|w&6EwGxERMm32{6|adN{lmCnO=?!|jUP3Ws1;e!SWGzjeq)Lvs!ZTTq&ie5vo- z`1p%Yqwt8KsRfc+Zbj`#L-1}(Bwi~Ax5qO&ZU@{ejQ+Hp4mt4VPoV_VeCr(6zF z9UR1ae&+2iX+s6E2V}Lxc6ZM+-8S6$a@?&Cn^C~=sPX~d#JLm;5Qw1n%IW*&PBV?q z09O(5{}gEc5xG_jOowcjF=x4y(&YamY5r}Y`?S#80Bh&J&-}>XgL{roRVEZo{x*i~ ziq&;TCj2%^Ju@%&4lTnyhe)5-5PDrQb*+9kAHW!EOaiu61g8cl_=CS1bA@HjhP}H5 zEBJUSKy2WF;ua_T{{-d-8TdvHidCA`BXq&j4cFtL z^yXVy20#nD1@%y@Y5U4sF1MvXa8K;F7B|Z;gH>tspveGY5S|}@U_A#|Imi?6GS1f%=ROP|BEkV#WqVG3b_;n2 z;H#;^adfh%ovD>w5Gs4>tI$7iJW3x%2mWus`fl%IFZf2qhN?JgWZYM_WBdsAyZ9Ln zRkEUt($@b`?c4fgl`7mn2lzu)}t zF)QPs=rMRr?Dp9+=yMv@`)?NKswHtVMS+34S>A@W)D9NFirDEhF)P8UhG0LzO-*O0 zw~iYtAHX;-bhAs~r#R<26~a<=Te-BB1z_}yavF7s_X>@Au~8kI-fv?*ch&2-MEDeRpn$| zQs#J6{sP}E#c@zKLH{=n*1NNgxp^;34)cyq+y$_nMaXHdPefdQB&ZYuaBF&F+#jI) z5iI(HZ*=0~V#^Xg^oqt{LGBS3`Mzzz-b6=qrl1#6B|u? z)MRjg9LIM9!?@uFajP;=#Ssg@2~wUs91pUhTWF1+X;!z;#!7zZ!HA3(S&VVh0-H-7)D5Ez?jhb5*13LRK%!y+ z0JbakM=Tfr@d$}P-7SM{#QqrU2pOeg#laPR_u*ECoxGxwD+5qp7mJFAC4KD`kx<@y z!H-TwF(`nXfja!2zxynS|Kfw?Nv{=+iYwx~iR_4 zsDFPJT72Tn&;L~mWIpqIHR?q6{H5=03xogjIQ00LT=Sm?Yu??dTo^X%GTU3y3 z5U%wt^lQ~lI;@oqpCR=JSG?o&&sGC)JkTBL$iPQn)gVhj=u1Ww=)nAbnfA|CTF1W} zHDFT%X57(fTIQ+HQ=ZLM-4b?z)=H^8gSHr jqXrx`;HZHtT?79Qd=?ufS>7*000000NkvXXu0mjfyH5ns literal 0 HcmV?d00001 diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval.c b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval.c new file mode 100644 index 00000000..ad4c8233 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval.c @@ -0,0 +1,1422 @@ +/** + ****************************************************************************** + * @file stm32756g_eval.c + * @author MCD Application Team + * @brief This file provides a set of firmware functions to manage LEDs, + * push-buttons and COM ports available on STM32756G-EVAL and STM32746G-EVAL + * evaluation board(MB1167) from STMicroelectronics. + * + @verbatim + This driver requires the stm32756g_eval_io.c/.h files to manage the + IO module resources mapped on the MFX IO expander. + These resources are mainly LEDs, Joystick push buttons, SD detect pin, + USB OTG power switch/over current drive pins, Camera plug pin, Audio + INT pin + The use of the above eval resources is conditioned by the "USE_IOEXPANDER" + preprocessor define which is enabled by default for the STM327x6G-EVAL + boards Rev A. However for Rev B boards these resources are disabled by default + (except LED1 and LED2) and to be able to use them, user must add "USE_IOEXPANDER" + define in the compiler preprocessor configuration (or any header file that + is processed before stm32756g_eval.h). + On the STM327x6G-EVAL RevB LED1 and LED2 are directly mapped on GPIO pins, + to avoid the unnecessary overhead of code brought by the use of MFX IO + expander when no further evaluation board resources are needed by the + application/example. + For precise details on the use of the MFX IO expander, you can refer to + the description provided within the stm32756g_eval_io.c file header + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32756g_eval_io.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_uart.c +- stm32f7xx_hal_i2c.c +- stm32f7xx_hal_adc.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval.h" +#if defined(USE_IOEXPANDER) +#include "stm32756g_eval_io.h" +#endif /* USE_IOEXPANDER */ + +/** @addtogroup BSP + * @{ + */ + +/** @defgroup STM32756G_EVAL EVAL + * @{ + */ + +/** @defgroup STM32756G_EVAL_LOW_LEVEL STM32756G-EVAL LOW LEVEL + * @{ + */ + +/** @defgroup STM32756G_EVAL_LOW_LEVEL_Private_TypesDefinitions STM32756G-EVAL LOW LEVEL Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LOW_LEVEL_Private_Defines STM32756G-EVAL LOW LEVEL Private Defines + * @{ + */ +/** + * @brief STM32756G EVAL BSP Driver version number V2.0.3 + */ +#define __STM32756G_EVAL_BSP_VERSION_MAIN (0x02) /*!< [31:24] main version */ +#define __STM32756G_EVAL_BSP_VERSION_SUB1 (0x00) /*!< [23:16] sub1 version */ +#define __STM32756G_EVAL_BSP_VERSION_SUB2 (0x03) /*!< [15:8] sub2 version */ +#define __STM32756G_EVAL_BSP_VERSION_RC (0x00) /*!< [7:0] release candidate */ +#define __STM32756G_EVAL_BSP_VERSION ((__STM32756G_EVAL_BSP_VERSION_MAIN << 24)\ + |(__STM32756G_EVAL_BSP_VERSION_SUB1 << 16)\ + |(__STM32756G_EVAL_BSP_VERSION_SUB2 << 8 )\ + |(__STM32756G_EVAL_BSP_VERSION_RC)) +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LOW_LEVEL_Private_Macros STM32756G-EVAL LOW LEVEL Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LOW_LEVEL_Private_Variables STM32756G-EVAL LOW LEVEL Private Variables + * @{ + */ + +#if defined(USE_IOEXPANDER) +const uint32_t GPIO_PIN[LEDn] = {LED1_PIN, + LED2_PIN, + LED3_PIN, + LED4_PIN}; +#else +const uint32_t GPIO_PIN[LEDn] = {LED1_PIN, + LED3_PIN}; +#endif /* USE_IOEXPANDER */ + + +GPIO_TypeDef* BUTTON_PORT[BUTTONn] = {WAKEUP_BUTTON_GPIO_PORT, + TAMPER_BUTTON_GPIO_PORT, + KEY_BUTTON_GPIO_PORT}; + +const uint16_t BUTTON_PIN[BUTTONn] = {WAKEUP_BUTTON_PIN, + TAMPER_BUTTON_PIN, + KEY_BUTTON_PIN}; + +const uint16_t BUTTON_IRQn[BUTTONn] = {WAKEUP_BUTTON_EXTI_IRQn, + TAMPER_BUTTON_EXTI_IRQn, + KEY_BUTTON_EXTI_IRQn}; + +USART_TypeDef* COM_USART[COMn] = {EVAL_COM1}; + +GPIO_TypeDef* COM_TX_PORT[COMn] = {EVAL_COM1_TX_GPIO_PORT}; + +GPIO_TypeDef* COM_RX_PORT[COMn] = {EVAL_COM1_RX_GPIO_PORT}; + +const uint16_t COM_TX_PIN[COMn] = {EVAL_COM1_TX_PIN}; + +const uint16_t COM_RX_PIN[COMn] = {EVAL_COM1_RX_PIN}; + +const uint16_t COM_TX_AF[COMn] = {EVAL_COM1_TX_AF}; + +const uint16_t COM_RX_AF[COMn] = {EVAL_COM1_RX_AF}; + +static I2C_HandleTypeDef hEvalI2c; +static ADC_HandleTypeDef hEvalADC; +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LOW_LEVEL_Private_FunctionPrototypes STM32756G_EVAL LOW LEVEL Private Function Prototypes + * @{ + */ +static void I2Cx_MspInit(void); +static void I2Cx_Init(void); +#if defined(USE_IOEXPANDER) +static void I2Cx_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +static uint8_t I2Cx_Read(uint8_t Addr, uint8_t Reg); +#endif /* USE_IOEXPANDER */ + +static HAL_StatusTypeDef I2Cx_ReadMultiple(uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static HAL_StatusTypeDef I2Cx_WriteMultiple(uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static HAL_StatusTypeDef I2Cx_IsDeviceReady(uint16_t DevAddress, uint32_t Trials); +static void I2Cx_Error(uint8_t Addr); + +#if defined(USE_IOEXPANDER) +/* IOExpander IO functions */ +void IOE_Init(void); +void IOE_ITConfig(void); +void IOE_Delay(uint32_t Delay); +void IOE_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +uint8_t IOE_Read(uint8_t Addr, uint8_t Reg); +uint16_t IOE_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); +void IOE_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); + +/* MFX IO functions */ +void MFX_IO_Init(void); +void MFX_IO_DeInit(void); +void MFX_IO_ITConfig(void); +void MFX_IO_Delay(uint32_t Delay); +void MFX_IO_Write(uint16_t Addr, uint8_t Reg, uint8_t Value); +uint8_t MFX_IO_Read(uint16_t Addr, uint8_t Reg); +uint16_t MFX_IO_ReadMultiple(uint16_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); +void MFX_IO_Wakeup(void); +void MFX_IO_EnableWakeupPin(void); +#endif /* USE_IOEXPANDER */ + +/* AUDIO IO functions */ +void AUDIO_IO_Init(void); +void AUDIO_IO_DeInit(void); +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value); +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg); +void AUDIO_IO_Delay(uint32_t Delay); + +/* CAMERA IO functions */ +void CAMERA_IO_Init(void); +void CAMERA_Delay(uint32_t Delay); +void CAMERA_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value); +uint16_t CAMERA_IO_Read(uint8_t Addr, uint16_t Reg); + +/* I2C EEPROM IO function */ +void EEPROM_IO_Init(void); +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials); +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LOW_LEVEL_Private_Functions STM32756G_EVAL LOW LEVEL Private Functions + * @{ + */ + + /** + * @brief This method returns the STM32756G EVAL BSP Driver revision + * @retval version: 0xXYZR (8bits for each decimal, R for RC) + */ +uint32_t BSP_GetVersion(void) +{ + return __STM32756G_EVAL_BSP_VERSION; +} + +/** + * @brief Configures LED on GPIO and/or on MFX. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @arg LED3 + * @arg LED4 + * @retval None + */ +void BSP_LED_Init(Led_TypeDef Led) +{ +#if !defined(USE_STM32756G_EVAL_REVA) + /* On RevB and above evaluation boards, LED1 and LED3 are connected to GPIOs */ + /* To use LED1 on RevB board, ensure that JP24 is in position 2-3, potentiometer is then no more usable */ + /* To use LED3 on RevB board, ensure that JP23 is in position 2-3, camera is then no more usable */ + GPIO_InitTypeDef gpio_init_structure; + GPIO_TypeDef* gpio_led; + + if ((Led == LED1) || (Led == LED3)) + { + if (Led == LED1) + { + gpio_led = LED1_GPIO_PORT; + /* Enable the GPIO_LED clock */ + LED1_GPIO_CLK_ENABLE(); + } + else + { + gpio_led = LED3_GPIO_PORT; + /* Enable the GPIO_LED clock */ + LED3_GPIO_CLK_ENABLE(); + } + + /* Configure the GPIO_LED pin */ + gpio_init_structure.Pin = GPIO_PIN[Led]; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + + HAL_GPIO_Init(gpio_led, &gpio_init_structure); + + /* By default, turn off LED */ + HAL_GPIO_WritePin(gpio_led, GPIO_PIN[Led], GPIO_PIN_SET); + } + else + { +#endif /* !USE_STM32756G_EVAL_REVA */ + +#if defined(USE_IOEXPANDER) + /* On RevA eval board, all LEDs are connected to MFX */ + /* On RevB and above eval board, LED2 and LED4 are connected to MFX */ + BSP_IO_Init(); /* Initialize MFX */ + BSP_IO_ConfigPin(GPIO_PIN[Led], IO_MODE_OUTPUT_PP_PU); + BSP_IO_WritePin(GPIO_PIN[Led], BSP_IO_PIN_SET); +#endif /* USE_IOEXPANDER */ + +#if !defined(USE_STM32756G_EVAL_REVA) + } +#endif /* !USE_STM32756G_EVAL_REVA */ +} + + +/** + * @brief DeInit LEDs. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @arg LED3 + * @arg LED4 + * @note Led DeInit does not disable the GPIO clock nor disable the Mfx + * @retval None + */ +void BSP_LED_DeInit(Led_TypeDef Led) +{ +#if !defined(USE_STM32756G_EVAL_REVA) + GPIO_InitTypeDef gpio_init_structure; + GPIO_TypeDef* gpio_led; + + /* On RevB led1 and Led3 are on GPIO while Led2 and Led4 on Mfx*/ + if ((Led == LED1) || (Led == LED3)) + { + if (Led == LED1) + { + gpio_led = LED1_GPIO_PORT; + } + else + { + gpio_led = LED3_GPIO_PORT; + } + /* Turn off LED */ + HAL_GPIO_WritePin(gpio_led, GPIO_PIN[Led], GPIO_PIN_RESET); + /* Configure the GPIO_LED pin */ + gpio_init_structure.Pin = GPIO_PIN[Led]; + HAL_GPIO_DeInit(gpio_led, gpio_init_structure.Pin); + } + else + { +#endif /* !USE_STM32756G_EVAL_REVA */ + +#if defined(USE_IOEXPANDER) /* (USE_IOEXPANDER always defined for RevA) */ + /* GPIO_PIN[Led] depends on the board revision: */ + /* - in case of RevA all leds are deinit */ + /* - in case of RevB just led 2 and led4 are deinit */ + BSP_IO_ConfigPin(GPIO_PIN[Led], IO_MODE_OFF); +#endif /* USE_IOEXPANDER */ + +#if !defined(USE_STM32756G_EVAL_REVA) + } +#endif /* !USE_STM32756G_EVAL_REVA */ +} + +/** + * @brief Turns selected LED On. + * @param Led: LED to be set on + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @arg LED3 + * @arg LED4 + * @retval None + */ +void BSP_LED_On(Led_TypeDef Led) +{ +#if !defined(USE_STM32756G_EVAL_REVA) + GPIO_TypeDef* gpio_led; + + if ((Led == LED1) || (Led == LED3)) /* Switch On LED connected to GPIO */ + { + if (Led == LED1) + { + gpio_led = LED1_GPIO_PORT; + } + else + { + gpio_led = LED3_GPIO_PORT; + } + HAL_GPIO_WritePin(gpio_led, GPIO_PIN[Led], GPIO_PIN_RESET); + } + else + { +#endif /* !USE_STM32756G_EVAL_REVA */ + +#if defined(USE_IOEXPANDER) /* Switch On LED connected to MFX */ + BSP_IO_WritePin(GPIO_PIN[Led], BSP_IO_PIN_RESET); +#endif /* USE_IOEXPANDER */ + +#if !defined(USE_STM32756G_EVAL_REVA) + } +#endif /* !USE_STM32756G_EVAL_REVA */ +} + +/** + * @brief Turns selected LED Off. + * @param Led: LED to be set off + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @arg LED3 + * @arg LED4 + * @retval None + */ +void BSP_LED_Off(Led_TypeDef Led) +{ +#if !defined(USE_STM32756G_EVAL_REVA) + GPIO_TypeDef* gpio_led; + + if ((Led == LED1) || (Led == LED3)) /* Switch Off LED connected to GPIO */ + { + if (Led == LED1) + { + gpio_led = LED1_GPIO_PORT; + } + else + { + gpio_led = LED3_GPIO_PORT; + } + HAL_GPIO_WritePin(gpio_led, GPIO_PIN[Led], GPIO_PIN_SET); + } + else + { +#endif /* !USE_STM32756G_EVAL_REVA */ + +#if defined(USE_IOEXPANDER) /* Switch Off LED connected to MFX */ + BSP_IO_WritePin(GPIO_PIN[Led], BSP_IO_PIN_SET); +#endif /* USE_IOEXPANDER */ + +#if !defined(USE_STM32756G_EVAL_REVA) + } +#endif /* !USE_STM32756G_EVAL_REVA */ + +} + +/** + * @brief Toggles the selected LED. + * @param Led: LED to be toggled + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @arg LED3 + * @arg LED4 + * @retval None + */ +void BSP_LED_Toggle(Led_TypeDef Led) +{ +#if !defined(USE_STM32756G_EVAL_REVA) + GPIO_TypeDef* gpio_led; + + if ((Led == LED1) || (Led == LED3)) /* Toggle LED connected to GPIO */ + { + if (Led == LED1) + { + gpio_led = LED1_GPIO_PORT; + } + else + { + gpio_led = LED3_GPIO_PORT; + } + HAL_GPIO_TogglePin(gpio_led, GPIO_PIN[Led]); + } + else + { +#endif /* !USE_STM32756G_EVAL_REVA */ + +#if defined(USE_IOEXPANDER) /* Toggle LED connected to MFX */ + BSP_IO_TogglePin(GPIO_PIN[Led]); +#endif /* USE_IOEXPANDER */ + +#if !defined(USE_STM32756G_EVAL_REVA) + } +#endif /* !USE_STM32756G_EVAL_REVA */ +} + +/** + * @brief Configures button GPIO and EXTI Line. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_TAMPER: Tamper Push Button + * @arg BUTTON_KEY: Key Push Button + * @param ButtonMode: Button mode + * This parameter can be one of the following values: + * @arg BUTTON_MODE_GPIO: Button will be used as simple IO + * @arg BUTTON_MODE_EXTI: Button will be connected to EXTI line + * with interrupt generation capability + * @note On STM32756G-EVAL evaluation board, the three buttons (Wakeup, Tamper + * and key buttons) are mapped on the same push button named "Wakeup/Tamper" + * on the board serigraphy. + * @retval None + */ +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef ButtonMode) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable the BUTTON clock */ + BUTTONx_GPIO_CLK_ENABLE(Button); + + if(ButtonMode == BUTTON_MODE_GPIO) + { + /* Configure Button pin as input */ + gpio_init_structure.Pin = BUTTON_PIN[Button]; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure); + } + + if(ButtonMode == BUTTON_MODE_EXTI) + { + /* Configure Button pin as input with External interrupt */ + gpio_init_structure.Pin = BUTTON_PIN[Button]; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + + if(Button != BUTTON_WAKEUP) + { + gpio_init_structure.Mode = GPIO_MODE_IT_FALLING; + } + else + { + gpio_init_structure.Mode = GPIO_MODE_IT_RISING; + } + + HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure); + + /* Enable and set Button EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(BUTTON_IRQn[Button]), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + } +} + +/** + * @brief Push Button DeInit. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_TAMPER: Tamper Push Button + * @arg BUTTON_KEY: Key Push Button + * @note On STM32756G-EVAL evaluation board, the three buttons (Wakeup, Tamper + * and key buttons) are mapped on the same push button named "Wakeup/Tamper" + * on the board serigraphy. + * @note PB DeInit does not disable the GPIO clock + * @retval None + */ +void BSP_PB_DeInit(Button_TypeDef Button) +{ + GPIO_InitTypeDef gpio_init_structure; + + gpio_init_structure.Pin = BUTTON_PIN[Button]; + HAL_NVIC_DisableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + HAL_GPIO_DeInit(BUTTON_PORT[Button], gpio_init_structure.Pin); +} + + +/** + * @brief Returns the selected button state. + * @param Button: Button to be checked + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_TAMPER: Tamper Push Button + * @arg BUTTON_KEY: Key Push Button + * @note On STM32756G-EVAL evaluation board, the three buttons (Wakeup, Tamper + * and key buttons) are mapped on the same push button named "Wakeup/Tamper" + * on the board serigraphy. + * @retval The Button GPIO pin value + */ +uint32_t BSP_PB_GetState(Button_TypeDef Button) +{ + return HAL_GPIO_ReadPin(BUTTON_PORT[Button], BUTTON_PIN[Button]); +} + +/** + * @brief Configures COM port. + * @param COM: COM port to be configured. + * This parameter can be one of the following values: + * @arg COM1 + * @arg COM2 + * @param huart: Pointer to a UART_HandleTypeDef structure that contains the + * configuration information for the specified USART peripheral. + * @retval None + */ +void BSP_COM_Init(COM_TypeDef COM, UART_HandleTypeDef *huart) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable GPIO clock */ + EVAL_COMx_TX_GPIO_CLK_ENABLE(COM); + EVAL_COMx_RX_GPIO_CLK_ENABLE(COM); + + /* Enable USART clock */ + EVAL_COMx_CLK_ENABLE(COM); + + /* Configure USART Tx as alternate function */ + gpio_init_structure.Pin = COM_TX_PIN[COM]; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Alternate = COM_TX_AF[COM]; + HAL_GPIO_Init(COM_TX_PORT[COM], &gpio_init_structure); + + /* Configure USART Rx as alternate function */ + gpio_init_structure.Pin = COM_RX_PIN[COM]; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = COM_RX_AF[COM]; + HAL_GPIO_Init(COM_RX_PORT[COM], &gpio_init_structure); + + /* USART configuration */ + huart->Instance = COM_USART[COM]; + HAL_UART_Init(huart); +} + +/** + * @brief DeInit COM port. + * @param COM: COM port to be configured. + * This parameter can be one of the following values: + * @arg COM1 + * @arg COM2 + * @param huart: Pointer to a UART_HandleTypeDef structure that contains the + * configuration information for the specified USART peripheral. + * @retval None + */ +void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart) +{ + /* USART configuration */ + huart->Instance = COM_USART[COM]; + HAL_UART_DeInit(huart); + + /* Enable USART clock */ + EVAL_COMx_CLK_DISABLE(COM); + + /* DeInit GPIO pins can be done in the application + (by surcharging this __weak function) */ + + /* GPIO pins clock, DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Init Potentiometer. + * @retval None + */ +void BSP_POTENTIOMETER_Init(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + ADC_ChannelConfTypeDef ADC_Config; + + /* ADC an GPIO Periph clock enable */ + ADCx_CLK_ENABLE(); + ADCx_CHANNEL_GPIO_CLK_ENABLE(); + + /* ADC Channel GPIO pin configuration */ + GPIO_InitStruct.Pin = ADCx_CHANNEL_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(ADCx_CHANNEL_GPIO_PORT, &GPIO_InitStruct); + + /* Configure the ADC peripheral */ + hEvalADC.Instance = ADCx; + + HAL_ADC_DeInit(&hEvalADC); + + hEvalADC.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4; /* Asynchronous clock mode, input ADC clock not divided */ + hEvalADC.Init.Resolution = ADC_RESOLUTION_12B; /* 12-bit resolution for converted data */ + hEvalADC.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* Right-alignment for converted data */ + hEvalADC.Init.ScanConvMode = DISABLE; /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */ + hEvalADC.Init.EOCSelection = DISABLE; /* EOC flag picked-up to indicate conversion end */ + hEvalADC.Init.ContinuousConvMode = DISABLE; /* Continuous mode disabled to have only 1 conversion at each conversion trig */ + hEvalADC.Init.NbrOfConversion = 1; /* Parameter discarded because sequencer is disabled */ + hEvalADC.Init.DiscontinuousConvMode = DISABLE; /* Parameter discarded because sequencer is disabled */ + hEvalADC.Init.NbrOfDiscConversion = 0; /* Parameter discarded because sequencer is disabled */ + hEvalADC.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; /* Software start to trig the 1st conversion manually, without external event */ + hEvalADC.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Parameter discarded because software trigger chosen */ + hEvalADC.Init.DMAContinuousRequests = DISABLE; /* DMA one-shot mode selected */ + + + HAL_ADC_Init(&hEvalADC); + + /* Configure ADC regular channel */ + ADC_Config.Channel = ADCx_CHANNEL; /* Sampled channel number */ + ADC_Config.Rank = 1; /* Rank of sampled channel number ADCx_CHANNEL */ + ADC_Config.SamplingTime = ADC_SAMPLETIME_3CYCLES; /* Sampling time (number of clock cycles unit) */ + ADC_Config.Offset = 0; /* Parameter discarded because offset correction is disabled */ + + HAL_ADC_ConfigChannel(&hEvalADC, &ADC_Config); +} + +/** + * @brief Get Potentiometer level in 12 bits. + * @retval Potentiometer level(0..0xFFF) / 0xFFFFFFFF : Error + */ +uint32_t BSP_POTENTIOMETER_GetLevel(void) +{ + if(HAL_ADC_Start(&hEvalADC) == HAL_OK) + { + if(HAL_ADC_PollForConversion(&hEvalADC, ADCx_POLL_TIMEOUT)== HAL_OK) + { + return (HAL_ADC_GetValue(&hEvalADC)); + } + } + return 0xFFFFFFFF; +} + +#if defined(USE_IOEXPANDER) +/** + * @brief Configures joystick GPIO and EXTI modes. + * @param JoyMode: Button mode. + * This parameter can be one of the following values: + * @arg JOY_MODE_GPIO: Joystick pins will be used as simple IOs + * @arg JOY_MODE_EXTI: Joystick pins will be connected to EXTI line + * with interrupt generation capability + * @retval IO_OK: if all initializations are OK. Other value if error. + */ +uint8_t BSP_JOY_Init(JOYMode_TypeDef JoyMode) +{ + uint8_t ret = 0; + + /* Initialize the IO functionalities */ + ret = BSP_IO_Init(); + + /* Configure joystick pins in IT mode */ + if(JoyMode == JOY_MODE_EXTI) + { + /* Configure IO interrupt acquisition mode */ + BSP_IO_ConfigPin(JOY_ALL_PINS, IO_MODE_IT_LOW_LEVEL_PU); + } + else + { + BSP_IO_ConfigPin(JOY_ALL_PINS, IO_MODE_INPUT_PU); + } + + return ret; +} + + +/** + * @brief DeInit joystick GPIOs. + * @note JOY DeInit does not disable the MFX, just set the MFX pins in Off mode + * @retval None. + */ +void BSP_JOY_DeInit() +{ + BSP_IO_ConfigPin(JOY_ALL_PINS, IO_MODE_OFF); +} + +/** + * @brief Returns the current joystick status. + * @retval Code of the joystick key pressed + * This code can be one of the following values: + * @arg JOY_NONE + * @arg JOY_SEL + * @arg JOY_DOWN + * @arg JOY_LEFT + * @arg JOY_RIGHT + * @arg JOY_UP + */ +JOYState_TypeDef BSP_JOY_GetState(void) +{ + uint16_t pin_status = 0; + + /* Read the status joystick pins */ + pin_status = BSP_IO_ReadPin(JOY_ALL_PINS); + + /* Check the pressed keys */ + if((pin_status & JOY_NONE_PIN) == JOY_NONE) + { + return(JOYState_TypeDef) JOY_NONE; + } + else if(!(pin_status & JOY_SEL_PIN)) + { + return(JOYState_TypeDef) JOY_SEL; + } + else if(!(pin_status & JOY_DOWN_PIN)) + { + return(JOYState_TypeDef) JOY_DOWN; + } + else if(!(pin_status & JOY_LEFT_PIN)) + { + return(JOYState_TypeDef) JOY_LEFT; + } + else if(!(pin_status & JOY_RIGHT_PIN)) + { + return(JOYState_TypeDef) JOY_RIGHT; + } + else if(!(pin_status & JOY_UP_PIN)) + { + return(JOYState_TypeDef) JOY_UP; + } + else + { + return(JOYState_TypeDef) JOY_NONE; + } +} + +/** + * @brief Check TS3510 touch screen presence + * @retval Return 0 if TS3510 is detected, return 1 if not detected + */ +uint8_t BSP_TS3510_IsDetected(void) +{ + HAL_StatusTypeDef status = HAL_OK; + uint32_t error = 0; + uint8_t a_buffer; + + uint8_t tmp_buffer[2] = {0x81, 0x08}; + + /* Prepare for LCD read data */ + IOE_WriteMultiple(TS3510_I2C_ADDRESS, 0x8A, tmp_buffer, 2); + + status = HAL_I2C_Mem_Read(&hEvalI2c, TS3510_I2C_ADDRESS, 0x8A, I2C_MEMADD_SIZE_8BIT, &a_buffer, 1, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + error = (uint32_t)HAL_I2C_GetError(&hEvalI2c); + + /* I2C error occurred */ + I2Cx_Error(TS3510_I2C_ADDRESS); + + if(error == HAL_I2C_ERROR_AF) + { + return 1; + } + } + return 0; +} +#endif /* USE_IOEXPANDER */ + +/******************************************************************************* + BUS OPERATIONS +*******************************************************************************/ + +/******************************* I2C Routines *********************************/ +/** + * @brief Initializes I2C MSP. + * @retval None + */ +static void I2Cx_MspInit(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + EVAL_I2Cx_SCL_SDA_GPIO_CLK_ENABLE(); + + /* Configure I2C Tx as alternate function */ + gpio_init_structure.Pin = EVAL_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = EVAL_I2Cx_SCL_SDA_AF; + HAL_GPIO_Init(EVAL_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C Rx as alternate function */ + gpio_init_structure.Pin = EVAL_I2Cx_SDA_PIN; + HAL_GPIO_Init(EVAL_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + EVAL_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + EVAL_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + EVAL_I2Cx_RELEASE_RESET(); + + /* Enable and set I2Cx Interrupt to a lower priority */ + HAL_NVIC_SetPriority(EVAL_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(EVAL_I2Cx_EV_IRQn); + + /* Enable and set I2Cx Interrupt to a lower priority */ + HAL_NVIC_SetPriority(EVAL_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(EVAL_I2Cx_ER_IRQn); +} + +/** + * @brief Initializes I2C HAL. + * @retval None + */ +static void I2Cx_Init(void) +{ + if(HAL_I2C_GetState(&hEvalI2c) == HAL_I2C_STATE_RESET) + { + hEvalI2c.Instance = EVAL_I2Cx; + hEvalI2c.Init.Timing = EVAL_I2Cx_TIMING; + hEvalI2c.Init.OwnAddress1 = 0; + hEvalI2c.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + hEvalI2c.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + hEvalI2c.Init.OwnAddress2 = 0; + hEvalI2c.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + hEvalI2c.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + + /* Init the I2C */ + I2Cx_MspInit(); + HAL_I2C_Init(&hEvalI2c); + } +} + + +#if defined(USE_IOEXPANDER) +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Value: Data to be written + * @retval None + */ +static void I2Cx_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Write(&hEvalI2c, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, &Value, 1, 100); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* Execute user timeout callback */ + I2Cx_Error(Addr); + } +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Register address + * @retval Read data + */ +static uint8_t I2Cx_Read(uint8_t Addr, uint8_t Reg) +{ + HAL_StatusTypeDef status = HAL_OK; + uint8_t Value = 0; + + status = HAL_I2C_Mem_Read(&hEvalI2c, Addr, Reg, I2C_MEMADD_SIZE_8BIT, &Value, 1, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* Execute user timeout callback */ + I2Cx_Error(Addr); + } + return Value; +} +#endif /* USE_IOEXPANDER */ + +/** + * @brief Reads multiple data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param MemAddress: Internal memory address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval Number of read data + */ +static HAL_StatusTypeDef I2Cx_ReadMultiple(uint8_t Addr, uint16_t Reg, uint16_t MemAddress, uint8_t *Buffer, uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + if(Addr == EXC7200_I2C_ADDRESS) + { + status = HAL_I2C_Master_Receive(&hEvalI2c, Addr, Buffer, Length, 1000); + } + else + { + status = HAL_I2C_Mem_Read(&hEvalI2c, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + } + + /* Check the communication status */ + if(status != HAL_OK) + { + /* I2C error occurred */ + I2Cx_Error(Addr); + } + return status; +} + +/** + * @brief Writes a value in a register of the device through BUS in using DMA mode. + * @param Addr: Device address on BUS Bus. + * @param Reg: The target register address to write + * @param MemAddress: Internal memory address + * @param Buffer: The target register value to be written + * @param Length: buffer size to be written + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_WriteMultiple(uint8_t Addr, uint16_t Reg, uint16_t MemAddress, uint8_t *Buffer, uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Write(&hEvalI2c, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* Re-Initiaize the I2C Bus */ + I2Cx_Error(Addr); + } + return status; +} + +/** + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param DevAddress: Target device address + * @param Trials: Number of trials + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_IsDeviceReady(uint16_t DevAddress, uint32_t Trials) +{ + return (HAL_I2C_IsDeviceReady(&hEvalI2c, DevAddress, Trials, 1000)); +} + +/** + * @brief Manages error callback by re-initializing I2C. + * @param Addr: I2C Address + * @retval None + */ +static void I2Cx_Error(uint8_t Addr) +{ + /* De-initialize the I2C communication bus */ + HAL_I2C_DeInit(&hEvalI2c); + + /* Re-Initialize the I2C communication bus */ + I2Cx_Init(); +} + +/******************************************************************************* + LINK OPERATIONS +*******************************************************************************/ + +/********************************* LINK IOE ***********************************/ +#if defined(USE_IOEXPANDER) +/** + * @brief Initializes IOE low level. + * @retval None + */ +void IOE_Init(void) +{ + I2Cx_Init(); +} + +/** + * @brief Configures IOE low level interrupt. + * @retval None + */ +void IOE_ITConfig(void) +{ + /* STMPE811 IO expander IT config done by BSP_TS_ITConfig function */ +} + +/** + * @brief IOE writes single data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Value: Data to be written + * @retval None + */ +void IOE_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_Write(Addr, Reg, Value); +} + +/** + * @brief IOE reads single data. + * @param Addr: I2C address + * @param Reg: Register address + * @retval Read data + */ +uint8_t IOE_Read(uint8_t Addr, uint8_t Reg) +{ + return I2Cx_Read(Addr, Reg); +} + +/** + * @brief IOE reads multiple data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval Number of read data + */ +uint16_t IOE_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + return I2Cx_ReadMultiple(Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief IOE writes multiple data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval None + */ +void IOE_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + I2Cx_WriteMultiple(Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief IOE delay + * @param Delay: Delay in ms + * @retval None + */ +void IOE_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} +#endif /* USE_IOEXPANDER */ + +/********************************* LINK MFX ***********************************/ + +#if defined(USE_IOEXPANDER) +/** + * @brief Initializes MFX low level. + * @retval None + */ +void MFX_IO_Init(void) +{ + I2Cx_Init(); +} + +/** + * @brief DeInitializes MFX low level. + * @retval None + */ +void MFX_IO_DeInit(void) +{ +} + +/** + * @brief Configures MFX low level interrupt. + * @retval None + */ +void MFX_IO_ITConfig(void) +{ + static uint8_t mfx_io_it_enabled = 0; + GPIO_InitTypeDef gpio_init_structure; + + if(mfx_io_it_enabled == 0) + { + mfx_io_it_enabled = 1; + /* Enable the GPIO EXTI clock */ + __HAL_RCC_GPIOI_CLK_ENABLE(); + __HAL_RCC_SYSCFG_CLK_ENABLE(); + + gpio_init_structure.Pin = GPIO_PIN_8; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_LOW; + gpio_init_structure.Mode = GPIO_MODE_IT_RISING; + HAL_GPIO_Init(GPIOI, &gpio_init_structure); + + /* Enable and set GPIO EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(EXTI9_5_IRQn), 0x0F, 0x0F); + HAL_NVIC_EnableIRQ((IRQn_Type)(EXTI9_5_IRQn)); + } +} + +/** + * @brief MFX writes single data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Value: Data to be written + * @retval None + */ +void MFX_IO_Write(uint16_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_Write((uint8_t) Addr, Reg, Value); +} + +/** + * @brief MFX reads single data. + * @param Addr: I2C address + * @param Reg: Register address + * @retval Read data + */ +uint8_t MFX_IO_Read(uint16_t Addr, uint8_t Reg) +{ + return I2Cx_Read((uint8_t) Addr, Reg); +} + +/** + * @brief MFX reads multiple data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval Number of read data + */ +uint16_t MFX_IO_ReadMultiple(uint16_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + return I2Cx_ReadMultiple((uint8_t)Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief MFX delay + * @param Delay: Delay in ms + * @retval None + */ +void MFX_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/** + * @brief Used by Lx family but requested for MFX component compatibility. + * @retval None + */ +void MFX_IO_Wakeup(void) +{ +} + +/** + * @brief Used by Lx family but requested for MXF component compatibility. + * @retval None + */ +void MFX_IO_EnableWakeupPin(void) +{ +} + +#endif /* USE_IOEXPANDER */ + +/********************************* LINK AUDIO *********************************/ + +/** + * @brief Initializes Audio low level. + * @retval None + */ +void AUDIO_IO_Init(void) +{ + I2Cx_Init(); +} + +/** + * @brief Deinitializes Audio low level. + * @retval None + */ +void AUDIO_IO_DeInit(void) +{ +} + +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param Value: Data to be written + * @retval None + */ +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value) +{ + uint16_t tmp = Value; + + Value = ((uint16_t)(tmp >> 8) & 0x00FF); + + Value |= ((uint16_t)(tmp << 8)& 0xFF00); + + I2Cx_WriteMultiple(Addr, Reg, I2C_MEMADD_SIZE_16BIT,(uint8_t*)&Value, 2); +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @retval Data to be read + */ +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg) +{ + uint16_t read_value = 0, tmp = 0; + + I2Cx_ReadMultiple(Addr, Reg, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&read_value, 2); + + tmp = ((uint16_t)(read_value >> 8) & 0x00FF); + + tmp |= ((uint16_t)(read_value << 8)& 0xFF00); + + read_value = tmp; + + return read_value; +} + +/** + * @brief AUDIO Codec delay + * @param Delay: Delay in ms + * @retval None + */ +void AUDIO_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/********************************* LINK CAMERA ********************************/ + +/** + * @brief Initializes Camera low level. + * @retval None + */ +void CAMERA_IO_Init(void) +{ + I2Cx_Init(); +} + +/** + * @brief Camera writes single data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Value: Data to be written + * @retval None + */ +void CAMERA_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value) +{ + uint16_t tmp = Value; + + if(Addr == CAMERA_I2C_ADDRESS_2) + { + I2Cx_WriteMultiple(Addr, Reg, I2C_MEMADD_SIZE_16BIT,(uint8_t*)&Value, 1); + } + else + { + /* For S5K5CAG sensor, 16 bits accesses are used */ + Value = ((uint16_t)(tmp >> 8) & 0x00FF); + Value |= ((uint16_t)(tmp << 8)& 0xFF00); + I2Cx_WriteMultiple(Addr, Reg, I2C_MEMADD_SIZE_16BIT,(uint8_t*)&Value, 2); + } +} + +/** + * @brief Camera reads single data. + * @param Addr: I2C address + * @param Reg: Register address + * @retval Read data + */ +uint16_t CAMERA_IO_Read(uint8_t Addr, uint16_t Reg) +{ + uint16_t read_value = 0, tmp = 0; + + if(Addr == CAMERA_I2C_ADDRESS_2) + { + I2Cx_ReadMultiple(Addr , Reg, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&read_value, 1); + } + else + { + /* For S5K5CAG sensor, 16 bits accesses are used */ + I2Cx_ReadMultiple(Addr, Reg, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&read_value, 2); + tmp = ((uint16_t)(read_value >> 8) & 0x00FF); + tmp |= ((uint16_t)(read_value << 8)& 0xFF00); + read_value = tmp; + } + + return read_value; +} + +/** + * @brief Camera delay + * @param Delay: Delay in ms + * @retval None + */ +void CAMERA_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/******************************** LINK I2C EEPROM *****************************/ + +/** + * @brief Initializes peripherals used by the I2C EEPROM driver. + * @retval None + */ +void EEPROM_IO_Init(void) +{ + I2Cx_Init(); +} + +/** + * @brief Write data to I2C EEPROM driver in using DMA channel. + * @param DevAddress: Target device address + * @param MemAddress: Internal memory address + * @param pBuffer: Pointer to data buffer + * @param BufferSize: Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize) +{ + return (I2Cx_WriteMultiple(DevAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, pBuffer, BufferSize)); +} + +/** + * @brief Read data from I2C EEPROM driver in using DMA channel. + * @param DevAddress: Target device address + * @param MemAddress: Internal memory address + * @param pBuffer: Pointer to data buffer + * @param BufferSize: Amount of data to be read + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize) +{ + return (I2Cx_ReadMultiple(DevAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, pBuffer, BufferSize)); +} + +/** + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param DevAddress: Target device address + * @param Trials: Number of trials + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials) +{ + return (I2Cx_IsDeviceReady(DevAddress, Trials)); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval.h b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval.h new file mode 100644 index 00000000..13fe9cb1 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval.h @@ -0,0 +1,430 @@ +/** + ****************************************************************************** + * @file stm32756g_eval.h + * @author MCD Application Team + * @brief This file contains definitions for STM32756G_EVAL and STM32746G_EVAL LEDs, + * push-buttons and COM ports hardware resources. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32756G_EVAL_H +#define __STM32756G_EVAL_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* USE_STM32756G_EVAL_REVA must USE USE_IOEXPANDER */ +#if defined(USE_STM32756G_EVAL_REVA) +#ifndef USE_IOEXPANDER +#define USE_IOEXPANDER +#endif /* USE_IOEXPANDER */ +#endif /* USE_STM32756G_EVAL_REVA */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @addtogroup STM32756G_EVAL_LOW_LEVEL + * @{ + */ + +/** @defgroup STM32756G_EVAL_LOW_LEVEL_Exported_Types LEVEL Exported Types + * @{ + */ +typedef enum +{ +#if defined(USE_IOEXPANDER) +LED1 = 0, +LED_GREEN = LED1, +LED2 = 1, +LED_ORANGE = LED2, +LED3 = 2, +LED_RED = LED3, +LED4 = 3, +LED_BLUE = LED4 +#else +LED1 = 0, +LED_GREEN = LED1, +LED3 = 1, +LED_RED = LED3, +#endif /* USE_IOEXPANDER */ +}Led_TypeDef; + +typedef enum +{ + BUTTON_WAKEUP = 0, + BUTTON_TAMPER = 1, + BUTTON_KEY = 2 +}Button_TypeDef; + +typedef enum +{ + BUTTON_MODE_GPIO = 0, + BUTTON_MODE_EXTI = 1 +}ButtonMode_TypeDef; + +#if defined(USE_IOEXPANDER) +typedef enum +{ + JOY_MODE_GPIO = 0, + JOY_MODE_EXTI = 1 +}JOYMode_TypeDef; + +typedef enum +{ + JOY_NONE = 0, + JOY_SEL = 1, + JOY_DOWN = 2, + JOY_LEFT = 3, + JOY_RIGHT = 4, + JOY_UP = 5 +}JOYState_TypeDef; +#endif /* USE_IOEXPANDER */ + +typedef enum +{ + COM1 = 0, + COM2 = 1 +}COM_TypeDef; +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LOW_LEVEL_Exported_Constants LOW LEVEL Exported Constants + * @{ + */ + +/** + * @brief Define for STM32756G_EVAL board + */ +#if !defined (USE_STM32756G_EVAL) + #define USE_STM32756G_EVAL +#endif + +/** @addtogroup STM32756G_EVAL_LOW_LEVEL_LED + * @{ + */ + +#if !defined(USE_STM32756G_EVAL_REVA) + +#if defined(USE_IOEXPANDER) +#define LEDn ((uint8_t)4) +#define LED2_PIN IO_PIN_17 +#define LED4_PIN IO_PIN_19 +#else +#define LEDn ((uint8_t)2) +#endif /* USE_IOEXPANDER */ + +#define LED1_GPIO_PORT GPIOF +#define LED1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() +#define LED1_GPIO_CLK_DISABLE() __HAL_RCC_GPIOF_CLK_DISABLE() +#define LED1_PIN GPIO_PIN_10 /* To use LED1, ensure that JP24 is in position 2-3, potentiometer is then no more usable */ + +#define LED3_GPIO_PORT GPIOB +#define LED3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define LED3_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE() +#define LED3_PIN GPIO_PIN_7 /* To use LED3, ensure that JP23 is in position 2-3, camera is then no more usable */ + +#else + +#define LEDn ((uint8_t)4) +#define LED1_PIN IO_PIN_16 +#define LED2_PIN IO_PIN_17 +#define LED3_PIN IO_PIN_18 +#define LED4_PIN IO_PIN_19 + +#endif /* !USE_STM32756G_EVAL_REVA */ + +/** + * @} + */ + +/** + * @brief MFX_IRQOUt pin + */ +#define MFX_IRQOUT_PIN GPIO_PIN_8 +#define MFX_IRQOUT_GPIO_PORT GPIOI +#define MFX_IRQOUT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define MFX_IRQOUT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define MFX_IRQOUT_EXTI_IRQn EXTI9_5_IRQn + +/** @addtogroup STM32756G_EVAL_LOW_LEVEL_BUTTON + * @{ + */ +/* Joystick pins are connected to IO Expander (accessible through I2C1 interface) */ +#define BUTTONn ((uint8_t)3) + +/** + * @brief Wakeup push-button + */ +#define WAKEUP_BUTTON_PIN GPIO_PIN_13 +#define WAKEUP_BUTTON_GPIO_PORT GPIOC +#define WAKEUP_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define WAKEUP_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE() +#define WAKEUP_BUTTON_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief Tamper push-button + */ +#define TAMPER_BUTTON_PIN GPIO_PIN_13 +#define TAMPER_BUTTON_GPIO_PORT GPIOC +#define TAMPER_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define TAMPER_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE() +#define TAMPER_BUTTON_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief Key push-button + */ +#define KEY_BUTTON_PIN GPIO_PIN_13 +#define KEY_BUTTON_GPIO_PORT GPIOC +#define KEY_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define KEY_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE() +#define KEY_BUTTON_EXTI_IRQn EXTI15_10_IRQn + +#define BUTTONx_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == 0) WAKEUP_BUTTON_GPIO_CLK_ENABLE(); else\ + if((__INDEX__) == 1) TAMPER_BUTTON_GPIO_CLK_ENABLE(); else\ + KEY_BUTTON_GPIO_CLK_ENABLE(); } while(0) + +#define BUTTONx_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? WAKEUP_BUTTON_GPIO_CLK_DISABLE() :\ + ((__INDEX__) == 1) ? TAMPER_BUTTON_GPIO_CLK_DISABLE() : KEY_BUTTON_GPIO_CLK_DISABLE()) +/** + * @} + */ + +/** @addtogroup STM32756G_EVAL_LOW_LEVEL_COM + * @{ + */ +#define COMn ((uint8_t)1) + +/** + * @brief Definition for COM port1, connected to USART1 + */ +#define EVAL_COM1 USART1 +#define EVAL_COM1_CLK_ENABLE() __HAL_RCC_USART1_CLK_ENABLE() +#define EVAL_COM1_CLK_DISABLE() __HAL_RCC_USART1_CLK_DISABLE() + +#define EVAL_COM1_TX_PIN GPIO_PIN_9 +#define EVAL_COM1_TX_GPIO_PORT GPIOA +#define EVAL_COM1_TX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define EVAL_COM1_TX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define EVAL_COM1_TX_AF GPIO_AF7_USART1 + +#define EVAL_COM1_RX_PIN GPIO_PIN_10 +#define EVAL_COM1_RX_GPIO_PORT GPIOA +#define EVAL_COM1_RX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define EVAL_COM1_RX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define EVAL_COM1_RX_AF GPIO_AF7_USART1 + +#define EVAL_COM1_IRQn USART1_IRQn + +#define EVAL_COMx_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) EVAL_COM1_CLK_ENABLE(); } while(0) +#define EVAL_COMx_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? EVAL_COM1_CLK_DISABLE() : 0) + +#define EVAL_COMx_TX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) EVAL_COM1_TX_GPIO_CLK_ENABLE(); } while(0) +#define EVAL_COMx_TX_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? EVAL_COM1_TX_GPIO_CLK_DISABLE() : 0) + +#define EVAL_COMx_RX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) EVAL_COM1_RX_GPIO_CLK_ENABLE(); } while(0) +#define EVAL_COMx_RX_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? EVAL_COM1_RX_GPIO_CLK_DISABLE() : 0) + +/** + * @brief Definition for Potentiometer, connected to ADC3 + */ +#define ADCx ADC3 +#define ADCx_CLK_ENABLE() __HAL_RCC_ADC3_CLK_ENABLE() +#define ADCx_CHANNEL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() + +#define ADCx_FORCE_RESET() __HAL_RCC_ADC_FORCE_RESET() +#define ADCx_RELEASE_RESET() __HAL_RCC_ADC_RELEASE_RESET() + +/* Definition for ADCx Channel Pin */ +#define ADCx_CHANNEL_PIN GPIO_PIN_10 +#define ADCx_CHANNEL_GPIO_PORT GPIOF + +/* Definition for ADCx's Channel */ +#define ADCx_CHANNEL ADC_CHANNEL_8 +#define SAMPLINGTIME ADC_SAMPLETIME_3CYCLES +#define ADCx_POLL_TIMEOUT 10 + +/** + * @brief Joystick Pins definition + */ +#if defined(USE_IOEXPANDER) +#define JOY_SEL_PIN IO_PIN_0 +#define JOY_DOWN_PIN IO_PIN_1 +#define JOY_LEFT_PIN IO_PIN_2 +#define JOY_RIGHT_PIN IO_PIN_3 +#define JOY_UP_PIN IO_PIN_4 +#define JOY_NONE_PIN JOY_ALL_PINS +#define JOY_ALL_PINS (IO_PIN_0 | IO_PIN_1 | IO_PIN_2 | IO_PIN_3 | IO_PIN_4) +#endif /* USE_IOEXPANDER */ +/** + * @brief Eval Pins definition connected to MFX + */ + +#if defined(USE_IOEXPANDER) +#define XSDN_PIN IO_PIN_10 +#define MII_INT_PIN IO_PIN_13 +#define RSTI_PIN IO_PIN_11 +#define CAM_PLUG_PIN IO_PIN_12 +#define LCD_INT_PIN IO_PIN_14 +#define AUDIO_INT_PIN IO_PIN_5 +#define OTG_FS1_OVER_CURRENT_PIN IO_PIN_6 +#define OTG_FS1_POWER_SWITCH_PIN IO_PIN_7 +#define OTG_FS2_OVER_CURRENT_PIN IO_PIN_8 +#define OTG_FS2_POWER_SWITCH_PIN IO_PIN_9 +#define SD_DETECT_PIN IO_PIN_15 + +#endif /* USE_IOEXPANDER */ + + +/* Exported constant IO ------------------------------------------------------*/ + +/* The MFX_I2C_ADDR input pin selects the MFX I2C device address + MFX_I2C_ADDR input pin MFX I2C device address + 0 b: 1000 010x (0x84) + 1 b: 1000 011x (0x86) + This input is sampled during the MFX firmware startup. */ +#define IO_I2C_ADDRESS ((uint16_t)0x84) /*mfx MFX_I2C_ADDR 0*/ +#define IO_I2C_ADDRESS_2 ((uint16_t)0x86) /*mfx MFX_I2C_ADDR 1*/ +#define TS_I2C_ADDRESS ((uint16_t)0x82) /*stmpe811 used on MB1046 board */ +#define TS3510_I2C_ADDRESS ((uint16_t)0x80) +#define EXC7200_I2C_ADDRESS ((uint16_t)0x08) +#define CAMERA_I2C_ADDRESS ((uint16_t)0x5A) +#define CAMERA_I2C_ADDRESS_2 ((uint16_t)0x78) +#define AUDIO_I2C_ADDRESS ((uint16_t)0x34) +#define EEPROM_I2C_ADDRESS_A01 ((uint16_t)0xA0) +#define EEPROM_I2C_ADDRESS_A02 ((uint16_t)0xA6) +/* I2C clock speed configuration (in Hz) + WARNING: + Make sure that this define is not already declared in other files (ie. + stm32756G_eval.h file). It can be used in parallel by other modules. */ +#ifndef I2C_SPEED + #define I2C_SPEED ((uint32_t)100000) +#endif /* I2C_SPEED */ + +/* User can use this section to tailor I2Cx/I2Cx instance used and associated + resources */ +/* Definition for I2Cx clock resources */ +#define EVAL_I2Cx I2C1 +#define EVAL_I2Cx_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE() +#define EVAL_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE() +#define EVAL_I2Cx_SCL_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() + +#define EVAL_I2Cx_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET() +#define EVAL_I2Cx_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET() + +/* Definition for I2Cx Pins */ +#define EVAL_I2Cx_SCL_PIN GPIO_PIN_8 +#define EVAL_I2Cx_SCL_SDA_GPIO_PORT GPIOB +#define EVAL_I2Cx_SCL_SDA_AF GPIO_AF4_I2C1 +#define EVAL_I2Cx_SDA_PIN GPIO_PIN_9 + +/* I2C interrupt requests */ +#define EVAL_I2Cx_EV_IRQn I2C1_EV_IRQn +#define EVAL_I2Cx_ER_IRQn I2C1_ER_IRQn + +/* I2C TIMING Register define when I2C clock source is SYSCLK */ +/* I2C TIMING is calculated from APB1 source clock = 50 MHz */ +/* Due to the big MOFSET capacity for adapting the camera level the rising time is very large (>1us) */ +/* 0x40912732 takes in account the big rising and aims a clock of 100khz */ +#ifndef EVAL_I2Cx_TIMING +#define EVAL_I2Cx_TIMING ((uint32_t)0x40912732) +#endif /* EVAL_I2Cx_TIMING */ + +/** + * @} + */ + +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LOW_LEVEL_Exported_Macros LOW LEVEL Exported Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LOW_LEVEL_Exported_Functions LOW LEVEL Exported Functions + * @{ + */ +uint32_t BSP_GetVersion(void); +void BSP_LED_Init(Led_TypeDef Led); +void BSP_LED_DeInit(Led_TypeDef Led); +void BSP_LED_On(Led_TypeDef Led); +void BSP_LED_Off(Led_TypeDef Led); +void BSP_LED_Toggle(Led_TypeDef Led); +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef ButtonMode); +void BSP_PB_DeInit(Button_TypeDef Button); +uint32_t BSP_PB_GetState(Button_TypeDef Button); +void BSP_COM_Init(COM_TypeDef COM, UART_HandleTypeDef *husart); +void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart); +void BSP_POTENTIOMETER_Init(void); +uint32_t BSP_POTENTIOMETER_GetLevel(void); +#if defined(USE_IOEXPANDER) +uint8_t BSP_JOY_Init(JOYMode_TypeDef JoyMode); +void BSP_JOY_DeInit(void); +JOYState_TypeDef BSP_JOY_GetState(void); +uint8_t BSP_TS3510_IsDetected(void); +#endif /* USE_IOEXPANDER */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32756G_EVAL_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_audio.c b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_audio.c new file mode 100644 index 00000000..54e7a99e --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_audio.c @@ -0,0 +1,1396 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_audio.c + * @author MCD Application Team + * @brief This file provides the Audio driver for the STM32756G-EVAL and + * STM32746G_EVAL evaluation board. + @verbatim + How To use this driver: + ----------------------- + + This driver supports STM32F7xx devices on STM32756G-EVAL (MB1167) Evaluation boards. + + Call the function BSP_AUDIO_OUT_Init( + OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, + OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH) + Volume : Initial volume to be set (0 is min (mute), 100 is max (100%) + AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...) + this parameter is relative to the audio file/stream type. + ) + This function configures all the hardware required for the audio application (codec, I2C, SAI, + GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK. + If the returned value is different from AUDIO_OK or the function is stuck then the communication with + the codec or the MFX has failed (try to un-plug the power or reset device in this case). + - OUTPUT_DEVICE_SPEAKER : only speaker will be set as output for the audio stream. + - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream. + - OUTPUT_DEVICE_BOTH : both Speaker and Headphone are used as outputs for the audio stream + at the same time. + Note. On STM32756G-EVAL SAI_DMA is configured in CIRCULAR mode. Due to this the application + does NOT need to call BSP_AUDIO_OUT_ChangeBuffer() to assure streaming. + + Call the function BSP_EVAL_AUDIO_OUT_Play( + pBuffer: pointer to the audio data file address + Size : size of the buffer to be sent in Bytes + ) + to start playing (for the first time) from the audio file/stream. + + Call the function BSP_AUDIO_OUT_Pause() to pause playing + + Call the function BSP_AUDIO_OUT_Resume() to resume playing. + Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called + for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case). + Note. This function should be called only when the audio file is played or paused (not stopped). + + For each mode, you may need to implement the relative callback functions into your code. + The Callback functions are named AUDIO_OUT_XXX_CallBack() and only their prototypes are declared in + the stm32756g_eval_audio.h file. (refer to the example for more details on the callbacks implementations) + + To Stop playing, to modify the volume level, the frequency, the audio frame slot, + the device output mode the mute or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(), + AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetAudioFrameSlot(), BSP_AUDIO_OUT_SetOutputMode(), + BSP_AUDIO_OUT_SetMute() and BSP_AUDIO_OUT_Stop(). + + The driver API and the callback functions are at the end of the stm32756g_eval_audio.h file. + + Driver architecture: + -------------------- + + This driver provides the High Audio Layer: consists of the function API exported in the stm32756g_eval_audio.h file + (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...) + + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/ + providing the audio file/stream. These functions are also included as local functions into + the stm32756g_eval_audio.c file (I2Sx_Init(), I2Sx_DeInit(), SAIx_Init() and SAIx_DeInit()) + + Known Limitations: + ------------------ + 1- If the TDM Format used to play in parallel 2 audio Stream (the first Stream is configured in codec SLOT0 and second + Stream in SLOT1) the Pause/Resume, volume and mute feature will control the both streams. + 2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, + File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file. + 3- Supports only Stereo audio streaming. + 4- Supports only 16-bits audio data size. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32756g_eval.c +- stm32f7xx_hal_sai.c +- stm32f7xx_hal_i2s.c +- stm32f7xx_hal_tim.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- wm8994.c +- pdm2pcm_glo.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval_audio.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @defgroup STM32756G_EVAL_AUDIO STM32756G_EVAL AUDIO + * @brief This file includes the low layer driver for wm8994 Audio Codec + * available on STM32756G-EVAL evaluation board(MB1167). + * @{ + */ + +/** @defgroup STM32756G_EVAL_AUDIO_Private_Types STM32756G_EVAL_AUDIO Private Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_AUDIO_Private_Defines STM32756G_EVAL_AUDIO Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_AUDIO_Private_Macros STM32756G_EVAL_AUDIO Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_AUDIO_Private_Variables STM32756G_EVAL_AUDIO Private Variables + * @{ + */ +AUDIO_DrvTypeDef *audio_drv; +SAI_HandleTypeDef haudio_out_sai; +I2S_HandleTypeDef haudio_in_i2s; +TIM_HandleTypeDef haudio_tim; + +/* PDM filters params */ +PDM_Filter_Handler_t PDM_FilterHandler[2]; +PDM_Filter_Config_t PDM_FilterConfig[2]; + +uint8_t Channel_Demux[128] = { + 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03, + 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03, + 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07, + 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07, + 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03, + 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x02, 0x03, + 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07, + 0x04, 0x05, 0x04, 0x05, 0x06, 0x07, 0x06, 0x07, + 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b, + 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f, + 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f, + 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b, + 0x08, 0x09, 0x08, 0x09, 0x0a, 0x0b, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f, + 0x0c, 0x0d, 0x0c, 0x0d, 0x0e, 0x0f, 0x0e, 0x0f +}; + +uint16_t __IO AudioInVolume = DEFAULT_AUDIO_IN_VOLUME; + +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_AUDIO_Private_Function_Prototypes STM32756G_EVAL_AUDIO Private Function Prototypes + * @{ + */ +static void SAIx_Init(uint32_t AudioFreq); +static void SAIx_DeInit(void); +static void I2Sx_Init(uint32_t AudioFreq); +static void I2Sx_DeInit(void); +static void TIMx_IC_MspInit(TIM_HandleTypeDef *htim); +static void TIMx_IC_MspDeInit(TIM_HandleTypeDef *htim); +static void TIMx_Init(void); +static void TIMx_DeInit(void); +static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbrIn, uint32_t ChnlNbrOut); + +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_AUDIO_out_Private_Functions STM32756G_EVAL_AUDIO_Out Private Functions + * @{ + */ + +/** + * @brief Configures the audio peripherals. + * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * or OUTPUT_DEVICE_BOTH. + * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) + * @param AudioFreq: Audio frequency used to play the audio stream. + * @note The I2S PLL input clock must be done in the user application. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + + /* Disable SAI */ + SAIx_DeInit(); + + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ + haudio_out_sai.Instance = AUDIO_SAIx; + if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); + } + SAIx_Init(AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq); + } + + return ret; +} + +/** + * @brief Starts playing audio stream from a data buffer for a determined size. + * @param pBuffer: Pointer to the buffer + * @param Size: Number of audio data BYTES. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size) +{ + /* Call the audio Codec Play function */ + if(audio_drv->Play(AUDIO_I2C_ADDRESS, pBuffer, Size) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Update the Media layer and enable it for play */ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, DMA_MAX(Size / AUDIODATA_SIZE)); + + return AUDIO_OK; + } +} + +/** + * @brief Sends n-Bytes on the SAI interface. + * @param pData: pointer on data address + * @param Size: number of data to be written + * @retval None + */ +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size) +{ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pData, Size); +} + +/** + * @brief This function Pauses the audio file stream. In case + * of using DMA, the DMA Pause feature is used. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Pause(void) +{ + /* Call the Audio Codec Pause/Resume function */ + if(audio_drv->Pause(AUDIO_I2C_ADDRESS) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause function */ + HAL_SAI_DMAPause(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief This function Resumes the audio file stream. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Resume(void) +{ + /* Call the Audio Codec Pause/Resume function */ + if(audio_drv->Resume(AUDIO_I2C_ADDRESS) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause/resume function */ + HAL_SAI_DMAResume(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Stops audio playing and Power down the Audio Codec. + * @param Option: could be one of the following parameters + * - CODEC_PDWN_SW: for software power off (by writing registers). + * Then no need to reconfigure the Codec after power on. + * - CODEC_PDWN_HW: completely shut down the codec (physically). + * Then need to reconfigure the Codec after power on. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option) +{ + /* Call the Media layer stop function */ + HAL_SAI_DMAStop(&haudio_out_sai); + + /* Call Audio Codec Stop function */ + if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) + { + return AUDIO_ERROR; + } + else + { + if(Option == CODEC_PDWN_HW) + { + /* Wait at least 100us */ + HAL_Delay(1); + } + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Controls the current audio volume level. + * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for + * Mute and 100 for Max volume level). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume) +{ + /* Call the codec volume control function with converted volume value */ + if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Enables or disables the MUTE mode by software + * @param Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to + * unmute the codec and restore previous volume level. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd) +{ + /* Call the Codec Mute function */ + if(audio_drv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Switch dynamically (while audio file is played) the output target + * (speaker or headphone). + * @param Output: The audio output target: OUTPUT_DEVICE_SPEAKER, + * OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output) +{ + /* Call the Codec output device function */ + if(audio_drv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Updates the audio frequency. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frequency. + * @retval None + */ +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq) +{ + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frequency configuration */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Updates the Audio frame slot configuration. + * @param AudioFrameSlot: specifies the audio Frame slot + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frame slot. + * @retval None + */ +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot) +{ + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frame slot configuration */ + haudio_out_sai.SlotInit.SlotActive = AudioFrameSlot; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Deinit the audio peripherals. + * @retval None + */ +void BSP_AUDIO_OUT_DeInit(void) +{ + SAIx_DeInit(); + /* DeInit the SAI MSP : this __weak function can be rewritten by the application */ + BSP_AUDIO_OUT_MspDeInit(&haudio_out_sai, NULL); +} + +/** + * @brief Tx Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32756g_eval_audio.h) */ + BSP_AUDIO_OUT_TransferComplete_CallBack(); +} + +/** + * @brief Tx Half Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32756g_eval_audio.h) */ + BSP_AUDIO_OUT_HalfTransfer_CallBack(); +} + +/** + * @brief SAI error callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai) +{ + BSP_AUDIO_OUT_Error_CallBack(); +} + +/** + * @brief Manages the DMA full Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void) +{ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void) +{ +} + +/** + * @brief Manages the DMA FIFO error event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_Error_CallBack(void) +{ +} + +/** + * @brief Initializes BSP_AUDIO_OUT MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params) +{ + static DMA_HandleTypeDef hdma_sai_tx; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SAI clock */ + AUDIO_SAIx_CLK_ENABLE(); + + /* Enable GPIO clock */ + AUDIO_SAIx_MCLK_ENABLE(); + AUDIO_SAIx_SCK_SD_ENABLE(); + AUDIO_SAIx_FS_ENABLE(); + /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/ + gpio_init_structure.Pin = AUDIO_SAIx_FS_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_SAIx_FS_SD_MCLK_AF; + HAL_GPIO_Init(AUDIO_SAIx_FS_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_SAIx_SCK_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_SAIx_SCK_AF; + HAL_GPIO_Init(AUDIO_SAIx_SCK_SD_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_SAIx_SD_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_SAIx_FS_SD_MCLK_AF; + HAL_GPIO_Init(AUDIO_SAIx_SCK_SD_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_SAIx_MCLK_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_SAIx_FS_SD_MCLK_AF; + HAL_GPIO_Init(AUDIO_SAIx_MCLK_GPIO_PORT, &gpio_init_structure); + + /* Enable the DMA clock */ + AUDIO_SAIx_DMAx_CLK_ENABLE(); + + if(hsai->Instance == AUDIO_SAIx) + { + /* Configure the hdma_saiTx handle parameters */ + hdma_sai_tx.Init.Channel = AUDIO_SAIx_DMAx_CHANNEL; + hdma_sai_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_sai_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sai_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sai_tx.Init.PeriphDataAlignment = AUDIO_SAIx_DMAx_PERIPH_DATA_SIZE; + hdma_sai_tx.Init.MemDataAlignment = AUDIO_SAIx_DMAx_MEM_DATA_SIZE; + hdma_sai_tx.Init.Mode = DMA_CIRCULAR; + hdma_sai_tx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_sai_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + hdma_sai_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sai_tx.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_sai_tx.Init.PeriphBurst = DMA_PBURST_SINGLE; + + hdma_sai_tx.Instance = AUDIO_SAIx_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsai, hdmatx, hdma_sai_tx); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_tx); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hdma_sai_tx); + } + + /* SAI DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_SAIx_DMAx_IRQ); +} + +/** + * @brief Deinitializes SAI MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* SAI DMA IRQ Channel deactivation */ + HAL_NVIC_DisableIRQ(AUDIO_SAIx_DMAx_IRQ); + + if(hsai->Instance == AUDIO_SAIx) + { + /* Deinitialize the DMA stream */ + HAL_DMA_DeInit(hsai->hdmatx); + } + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(hsai); + + /* Deactivates CODEC_SAI pins FS, SCK, MCK and SD by putting them in input mode */ + gpio_init_structure.Pin = AUDIO_SAIx_FS_PIN; + HAL_GPIO_DeInit(AUDIO_SAIx_FS_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_SAIx_SCK_PIN; + HAL_GPIO_DeInit(AUDIO_SAIx_SCK_SD_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_SAIx_SD_PIN; + HAL_GPIO_DeInit(AUDIO_SAIx_SCK_SD_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_SAIx_MCLK_PIN; + HAL_GPIO_DeInit(AUDIO_SAIx_MCLK_GPIO_PORT, gpio_init_structure.Pin); + + /* Disable SAI clock */ + AUDIO_SAIx_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the applic + by surcharging this __weak function */ +} + +/** + * @brief Clock Config. + * @param hsai: might be required to set audio peripheral predivider if any. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @param Params + * @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(Params); + + RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; + + HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); + + /* Set the PLL configuration according to the audio frequency */ + if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) + { + /* Configure PLLSAI prescalers */ + /* PLLSAI_VCO: VCO_429M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 429/2 = 214.5 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 214.5/19 = 11.289 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLSAI; + rcc_ex_clk_init_struct.PLLSAI.PLLSAIN = 429; + rcc_ex_clk_init_struct.PLLSAI.PLLSAIQ = 2; + rcc_ex_clk_init_struct.PLLSAIDivQ = 19; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + + } + else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K), AUDIO_FREQUENCY_96K */ + { + /* SAI clock config + PLLSAI_VCO: VCO_344M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 344/7 = 49.142 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 49.142/1 = 49.142 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLSAI; + rcc_ex_clk_init_struct.PLLSAI.PLLSAIN = 344; + rcc_ex_clk_init_struct.PLLSAI.PLLSAIQ = 7; + rcc_ex_clk_init_struct.PLLSAIDivQ = 1; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + } +} + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Initializes the Audio Codec audio interface (SAI). + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @note The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123 + * and user can update this configuration using + * @retval None + */ +static void SAIx_Init(uint32_t AudioFreq) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + haudio_out_sai.Init.AudioMode = SAI_MODEMASTER_TX; + haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLED; + haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE; + haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; + haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLED; + haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_out_sai.FrameInit.FrameLength = 64; + haudio_out_sai.FrameInit.ActiveFrameLength = 32; + haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot actives */ + haudio_out_sai.SlotInit.FirstBitOffset = 0; + haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_out_sai.SlotInit.SlotNumber = 4; + haudio_out_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_0123; + + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Deinitializes the Audio Codec audio interface (SAI). + * @retval None + */ +static void SAIx_DeInit(void) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_SAIx; + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + HAL_SAI_DeInit(&haudio_out_sai); +} + +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_AUDIO_out_Private_Functions STM32756G_EVAL_AUDIO_Out Private Functions + * @{ + */ + +/** + * @brief Initializes wave recording. + * @note This function assumes that the I2S input clock (through PLL_R in + * Devices RevA/Z and through dedicated PLLI2S_R in Devices RevB/Y) + * is already configured and ready to be used. + * @param AudioFreq: Audio frequency to be configured for the I2S peripheral. + * @param BitRes: Audio frequency to be configured for the I2S peripheral. + * @param ChnlNbr: Audio frequency to be configured for the I2S peripheral. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + /* Disable I2S */ + I2Sx_DeInit(); + + /* Configure I2S PLL clock */ + BSP_AUDIO_IN_ClockConfig(&haudio_in_i2s, AudioFreq, NULL); + + /* Configure the PDM library */ + PDMDecoder_Init(AudioFreq, ChnlNbr, ChnlNbr); + + /* Configure the I2S peripheral */ + haudio_in_i2s.Instance = AUDIO_I2Sx; + if(HAL_I2S_GetState(&haudio_in_i2s) == HAL_I2S_STATE_RESET) + { + /* Initialize the I2S Msp: this __weak function can be rewritten by the application */ + BSP_AUDIO_IN_MspInit(&haudio_in_i2s, NULL); + } + I2Sx_Init(AudioFreq); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Starts audio recording. + * @param pbuf: Main buffer pointer for the recorded data storing + * @param size: Current size of the recorded buffer + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size) +{ + uint32_t ret = AUDIO_ERROR; + + /* Start the process receive DMA */ + HAL_I2S_Receive_DMA(&haudio_in_i2s, pbuf, size); + + /* Return AUDIO_OK when all operations are correctly done */ + ret = AUDIO_OK; + + return ret; +} + +/** + * @brief Stops audio recording. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Stop(void) +{ + uint32_t ret = AUDIO_ERROR; + /* Call the Media layer stop function */ + HAL_I2S_DMAStop(&haudio_in_i2s); + + /* TIMx Peripheral clock disable */ + AUDIO_TIMx_CLK_DISABLE(); + + /* Return AUDIO_OK when all operations are correctly done */ + ret = AUDIO_OK; + + return ret; +} + +/** + * @brief Pauses the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Pause(void) +{ + /* Call the Media layer pause function */ + HAL_I2S_DMAPause(&haudio_in_i2s); + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Resumes the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Resume(void) +{ + /* Call the Media layer pause/resume function */ + HAL_I2S_DMAResume(&haudio_in_i2s); + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Controls the audio in volume level. + * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for + * Mute and 100 for Max volume level). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume) +{ + /* Set the Global variable AudioInVolume */ + AudioInVolume = Volume; + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Deinit the audio IN peripherals. + * @retval None + */ +void BSP_AUDIO_IN_DeInit(void) +{ + I2Sx_DeInit(); + /* DeInit the I2S MSP : this __weak function can be rewritten by the application */ + BSP_AUDIO_IN_MspDeInit(&haudio_in_i2s, NULL); + TIMx_DeInit(); +} + +/** + * @brief Converts audio format from PDM to PCM. + * @param PDMBuf: Pointer to data PDM buffer + * @param PCMBuf: Pointer to data PCM buffer + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_PDMToPCM(uint16_t* PDMBuf, uint16_t* PCMBuf) +{ + uint8_t app_pdm[INTERNAL_BUFF_SIZE*2]; + uint8_t byte1 = 0, byte2 = 0; + uint32_t index = 0; + + /* PDM Demux */ + for(index = 0; index> 8)& 0xFF; + byte1 = (PDMBuf[index] & 0xFF); + app_pdm[(index*2)+1] = Channel_Demux[byte1 & CHANNEL_DEMUX_MASK] | Channel_Demux[byte2 & CHANNEL_DEMUX_MASK] << 4; + app_pdm[(index*2)] = Channel_Demux[(byte1 >> 1) & CHANNEL_DEMUX_MASK] | Channel_Demux[(byte2 >> 1) & CHANNEL_DEMUX_MASK] << 4; + } + + for(index = 0; index < DEFAULT_AUDIO_IN_CHANNEL_NBR; index++) + { + /* PDM to PCM filter */ + PDM_Filter((uint8_t*)&app_pdm[index], (uint16_t*)&(PCMBuf[index]), &PDM_FilterHandler[index]); + } + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + + /** + * @brief Rx Transfer completed callbacks. + * @param hi2s: I2S handle + * @retval None + */ +void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) +{ + /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ + BSP_AUDIO_IN_TransferComplete_CallBack(); +} + +/** + * @brief Rx Half Transfer completed callbacks. + * @param hi2s: I2S handle + * @retval None + */ +void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32756g_eval_audio.h) */ + BSP_AUDIO_IN_HalfTransfer_CallBack(); +} + +/** + * @brief I2S error callbacks. + * @param hi2s: I2S handle + * @retval None + */ +void HAL_I2S_ErrorCallback(I2S_HandleTypeDef *hi2s) +{ + /* Manage the error generated on DMA FIFO: This function + should be coded by user (its prototype is already declared in stm32756g_eval_audio.h) */ + BSP_AUDIO_IN_Error_Callback(); +} + +/** + * @brief User callback when record buffer is filled. + * @retval None + */ +__weak void BSP_AUDIO_IN_TransferComplete_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Audio IN Error callback function. + * @retval None + */ +__weak void BSP_AUDIO_IN_Error_Callback(void) +{ + /* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +} + +/** + * @brief Initializes BSP_AUDIO_IN MSP. + * @param hi2s: I2S handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_IN_MspInit(I2S_HandleTypeDef *hi2s, void *Params) +{ + static DMA_HandleTypeDef hdma_i2s_rx; + GPIO_InitTypeDef gpio_init_structure; + + /* Configure the Timer which clocks the MEMS */ + /* Moved inside MSP to allow applic to redefine the TIMx_MspInit */ + TIMx_Init(); + + /* Enable I2S clock */ + AUDIO_I2Sx_CLK_ENABLE(); + + /* Enable SCK and SD GPIO clock */ + AUDIO_I2Sx_SD_GPIO_CLK_ENABLE(); + AUDIO_I2Sx_SCK_GPIO_CLK_ENABLE(); + /* CODEC_I2S pins configuration: SCK and SD pins */ + gpio_init_structure.Pin = AUDIO_I2Sx_SCK_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = AUDIO_I2Sx_SCK_AF; + HAL_GPIO_Init(AUDIO_I2Sx_SCK_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_I2Sx_SD_PIN; + gpio_init_structure.Alternate = AUDIO_I2Sx_SD_AF; + HAL_GPIO_Init(AUDIO_I2Sx_SD_GPIO_PORT, &gpio_init_structure); + + /* Enable the DMA clock */ + AUDIO_I2Sx_DMAx_CLK_ENABLE(); + + if(hi2s->Instance == AUDIO_I2Sx) + { + /* Configure the hdma_i2s_rx handle parameters */ + hdma_i2s_rx.Init.Channel = AUDIO_I2Sx_DMAx_CHANNEL; + hdma_i2s_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_i2s_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_i2s_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_i2s_rx.Init.PeriphDataAlignment = AUDIO_I2Sx_DMAx_PERIPH_DATA_SIZE; + hdma_i2s_rx.Init.MemDataAlignment = AUDIO_I2Sx_DMAx_MEM_DATA_SIZE; + hdma_i2s_rx.Init.Mode = DMA_CIRCULAR; + hdma_i2s_rx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_i2s_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_i2s_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_i2s_rx.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_i2s_rx.Init.PeriphBurst = DMA_MBURST_SINGLE; + + hdma_i2s_rx.Instance = AUDIO_I2Sx_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hi2s, hdmarx, hdma_i2s_rx); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_i2s_rx); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hdma_i2s_rx); + } + + /* I2S DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_I2Sx_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_I2Sx_DMAx_IRQ); +} + +/** + * @brief DeInitializes BSP_AUDIO_IN MSP. + * @param hi2s: I2S handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_IN_MspDeInit(I2S_HandleTypeDef *hi2s, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + static DMA_HandleTypeDef hdma_i2s_rx; + + /* I2S DMA IRQ Channel deactivation */ + HAL_NVIC_DisableIRQ(AUDIO_I2Sx_DMAx_IRQ); + + if(hi2s->Instance == AUDIO_I2Sx) + { + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_i2s_rx); + } + + /* Disable I2S block */ + __HAL_I2S_DISABLE(hi2s); + + /* Disable pins: SCK and SD pins */ + gpio_init_structure.Pin = AUDIO_I2Sx_SCK_PIN; + HAL_GPIO_DeInit(AUDIO_I2Sx_SCK_GPIO_PORT, gpio_init_structure.Pin); + gpio_init_structure.Pin = AUDIO_I2Sx_SD_PIN; + HAL_GPIO_DeInit(AUDIO_I2Sx_SD_GPIO_PORT, gpio_init_structure.Pin); + + /* Disable I2S clock */ + AUDIO_I2Sx_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Clock Config. + * @param hi2s: might be required to set audio peripheral predivider if any. + * @param AudioFreq: Audio frequency used to record the audio stream. + * @param Params + * @note This API is called by BSP_AUDIO_IN_Init() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_AUDIO_IN_ClockConfig(I2S_HandleTypeDef *hi2s, uint32_t AudioFreq, void *Params) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(AudioFreq); + UNUSED(Params); + + RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; + + HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_I2S; + rcc_ex_clk_init_struct.I2sClockSelection = RCC_I2SCLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 384; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SR = 2; + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); +} + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Initializes the PDM library. + * @param AudioFreq: Audio sampling frequency + * @param ChnlNbrIn: Number of input audio channels in the PDM buffer + * @param ChnlNbrOut: Number of desired output audio channels in the resulting PCM buffer + * Number of audio channels (1: mono; 2: stereo) + */ +static void PDMDecoder_Init(uint32_t AudioFreq, uint32_t ChnlNbrIn, uint32_t ChnlNbrOut) +{ + uint32_t index = 0; + + /* Enable CRC peripheral to unlock the PDM library */ + __HAL_RCC_CRC_CLK_ENABLE(); + + for(index = 0; index < ChnlNbrIn; index++) + { + /* Init PDM filters */ + PDM_FilterHandler[index].bit_order = PDM_FILTER_BIT_ORDER_LSB; + PDM_FilterHandler[index].endianness = PDM_FILTER_ENDIANNESS_LE; + PDM_FilterHandler[index].high_pass_tap = 2122358088; + PDM_FilterHandler[index].out_ptr_channels = ChnlNbrOut; + PDM_FilterHandler[index].in_ptr_channels = ChnlNbrIn; + PDM_Filter_Init((PDM_Filter_Handler_t *)(&PDM_FilterHandler[index])); + + /* PDM lib config phase */ + PDM_FilterConfig[index].output_samples_number = AudioFreq/1000; + PDM_FilterConfig[index].mic_gain = 24; + PDM_FilterConfig[index].decimation_factor = PDM_FILTER_DEC_FACTOR_64; + PDM_Filter_setConfig((PDM_Filter_Handler_t *)&PDM_FilterHandler[index], &PDM_FilterConfig[index]); + } +} + +/** + * @brief Initializes the Audio Codec audio interface (I2S) + * @note This function assumes that the I2S input clock (through PLL_R in + * Devices RevA/Z and through dedicated PLLI2S_R in Devices RevB/Y) + * is already configured and ready to be used. + * @param AudioFreq: Audio frequency to be configured for the I2S peripheral. + * @retval None + */ +static void I2Sx_Init(uint32_t AudioFreq) +{ + /* Initialize the haudio_in_i2s Instance parameter */ + haudio_in_i2s.Instance = AUDIO_I2Sx; + + /* Disable I2S block */ + __HAL_I2S_DISABLE(&haudio_in_i2s); + + /* I2S2 peripheral configuration */ + haudio_in_i2s.Init.AudioFreq = 4 * AudioFreq; + haudio_in_i2s.Init.ClockSource = I2S_CLOCK_SYSCLK; + haudio_in_i2s.Init.CPOL = I2S_CPOL_HIGH; + haudio_in_i2s.Init.DataFormat = I2S_DATAFORMAT_16B; + haudio_in_i2s.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE; + haudio_in_i2s.Init.Mode = I2S_MODE_MASTER_RX; + haudio_in_i2s.Init.Standard = I2S_STANDARD_LSB; + + /* Init the I2S */ + HAL_I2S_Init(&haudio_in_i2s); + + /* Enable I2S peripheral */ + __HAL_I2S_ENABLE(&haudio_in_i2s); +} + +/** + * @brief Deinitializes the Audio Codec audio interface (I2S). + * @retval None + */ +static void I2Sx_DeInit(void) +{ + /* Initialize the haudio_in_i2s Instance parameter */ + haudio_in_i2s.Instance = AUDIO_I2Sx; + + /* Disable I2S block */ + __HAL_I2S_DISABLE(&haudio_in_i2s); + + /* DeInit the I2S */ + HAL_I2S_DeInit(&haudio_in_i2s); +} + + +/** + * @brief Initializes the TIM INput Capture MSP. + * @param htim: TIM handle + * @retval None + */ +static void TIMx_IC_MspInit(TIM_HandleTypeDef *htim) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable peripherals and GPIO Clocks --------------------------------------*/ + /* TIMx Peripheral clock enable */ + AUDIO_TIMx_CLK_ENABLE(); + + /* Enable GPIO Channels Clock */ + AUDIO_TIMx_GPIO_CLK_ENABLE(); + + /* Configure I/Os ----------------------------------------------------------*/ + /* Common configuration for all channels */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_TIMx_AF; + + /* Configure TIM input channel */ + gpio_init_structure.Pin = AUDIO_TIMx_IN_GPIO_PIN; + HAL_GPIO_Init(AUDIO_TIMx_GPIO_PORT, &gpio_init_structure); + + /* Configure TIM output channel */ + gpio_init_structure.Pin = AUDIO_TIMx_OUT_GPIO_PIN; + HAL_GPIO_Init(AUDIO_TIMx_GPIO_PORT, &gpio_init_structure); + +} + +/** + * @brief Initializes the TIM INput Capture MSP. + * @param htim: TIM handle + * @retval None + */ +static void TIMx_IC_MspDeInit(TIM_HandleTypeDef *htim) +{ + /* Disable TIMx Peripheral clock */ + AUDIO_TIMx_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Configure TIM as a clock divider by 2. + * I2S_SCK is externally connected to TIMx input channel + * @retval None + */ +static void TIMx_Init(void) +{ + TIM_IC_InitTypeDef s_ic_config; + TIM_OC_InitTypeDef s_oc_config; + TIM_ClockConfigTypeDef s_clk_source_config; + TIM_SlaveConfigTypeDef s_slave_config; + + /* Configure the TIM peripheral --------------------------------------------*/ + /* Set TIMx instance */ + haudio_tim.Instance = AUDIO_TIMx; + /* Timer Input Capture Configuration Structure declaration */ + /* Initialize TIMx peripheral as follow: + + Period = 0xFFFF + + Prescaler = 0 + + ClockDivision = 0 + + Counter direction = Up + */ + haudio_tim.Init.Period = 1; + haudio_tim.Init.Prescaler = 0; + haudio_tim.Init.ClockDivision = 0; + haudio_tim.Init.CounterMode = TIM_COUNTERMODE_UP; + + /* Initialize the TIMx peripheral with the structure above */ + TIMx_IC_MspInit(&haudio_tim); + HAL_TIM_IC_Init(&haudio_tim); + + /* Configure the Input Capture channel -------------------------------------*/ + /* Configure the Input Capture of channel 2 */ + s_ic_config.ICPolarity = TIM_ICPOLARITY_FALLING; + s_ic_config.ICSelection = TIM_ICSELECTION_DIRECTTI; + s_ic_config.ICPrescaler = TIM_ICPSC_DIV1; + s_ic_config.ICFilter = 0; + HAL_TIM_IC_ConfigChannel(&haudio_tim, &s_ic_config, AUDIO_TIMx_IN_CHANNEL); + + /* Select external clock mode 1 */ + s_clk_source_config.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; + s_clk_source_config.ClockPolarity = TIM_CLOCKPOLARITY_NONINVERTED; + s_clk_source_config.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1; + s_clk_source_config.ClockFilter = 0; + HAL_TIM_ConfigClockSource(&haudio_tim, &s_clk_source_config); + + /* Select Input Channel as input trigger */ + s_slave_config.InputTrigger = TIM_TS_TI1FP1; + s_slave_config.SlaveMode = TIM_SLAVEMODE_EXTERNAL1; + s_slave_config.TriggerPolarity = TIM_TRIGGERPOLARITY_NONINVERTED; + s_slave_config.TriggerPrescaler = TIM_CLOCKPRESCALER_DIV1; + s_slave_config.TriggerFilter = 0; + HAL_TIM_SlaveConfigSynchronization(&haudio_tim, &s_slave_config); + + /* Output Compare PWM Mode configuration: Channel2 */ + s_oc_config.OCMode = TIM_OCMODE_PWM1; + s_oc_config.OCIdleState = TIM_OCIDLESTATE_SET; + s_oc_config.Pulse = 1; + s_oc_config.OCPolarity = TIM_OCPOLARITY_HIGH; + s_oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH; + s_oc_config.OCFastMode = TIM_OCFAST_DISABLE; + s_oc_config.OCNIdleState = TIM_OCNIDLESTATE_SET; + + /* Initialize the TIM3 Channel2 with the structure above */ + HAL_TIM_PWM_ConfigChannel(&haudio_tim, &s_oc_config, AUDIO_TIMx_OUT_CHANNEL); + + /* Start the TIM3 Channel2 */ + HAL_TIM_PWM_Start(&haudio_tim, AUDIO_TIMx_OUT_CHANNEL); + + /* Start the TIM3 Channel1 */ + HAL_TIM_IC_Start(&haudio_tim, AUDIO_TIMx_IN_CHANNEL); +} + +/** + * @brief Configure TIM as a clock divider by 2. + * I2S_SCK is externally connected to TIMx input channel + * @retval None + */ +static void TIMx_DeInit(void) +{ + haudio_tim.Instance = AUDIO_TIMx; + + /* Stop the TIM4 Channel2 */ + HAL_TIM_PWM_Stop(&haudio_tim, AUDIO_TIMx_OUT_CHANNEL); + /* Stop the TIM4 Channel1 */ + HAL_TIM_IC_Stop(&haudio_tim, AUDIO_TIMx_IN_CHANNEL); + + HAL_TIM_IC_DeInit(&haudio_tim); + + /* Initialize the TIMx peripheral with the structure above */ + TIMx_IC_MspDeInit(&haudio_tim); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_audio.h b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_audio.h new file mode 100644 index 00000000..3b13d1c7 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_audio.h @@ -0,0 +1,319 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_audio.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32756g_eval_audio.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32756G_EVAL_AUDIO_H +#define __STM32756G_EVAL_AUDIO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include audio component Driver */ +#include "../Components/wm8994/wm8994.h" +#include "stm32756g_eval.h" +#include "../../../Middlewares/ST/STM32_Audio/Addons/PDM/Inc/pdm2pcm_glo.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @addtogroup STM32756G_EVAL_AUDIO STM32756G_EVAL AUDIO + * @{ + */ + +/** @defgroup STM32756G_EVAL_AUDIO_Exported_Types STM32756G_EVAL_AUDIO Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_AUDIO_Exported_Constants STM32756G_EVAL_AUDIO Exported Constants + * @{ + */ + +/*------------------------------------------------------------------------------ + USER SAI defines parameters + -----------------------------------------------------------------------------*/ +/** CODEC_AudioFrame_SLOT_TDMMode In W8994 codec the Audio frame contains 4 slots : TDM Mode + * TDM format : + * +------------------|------------------|--------------------|-------------------+ + * | CODEC_SLOT0 Left | CODEC_SLOT1 Left | CODEC_SLOT0 Right | CODEC_SLOT1 Right | + * +------------------------------------------------------------------------------+ + */ +/* To have 2 separate audio stream in Both headphone and speaker the 4 slot must be activated */ +#define CODEC_AUDIOFRAME_SLOT_0123 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_2 | SAI_SLOTACTIVE_3 +/* To have an audio stream in headphone only SAI Slot 0 and Slot 2 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_02 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_2 +/* To have an audio stream in speaker only SAI Slot 1 and Slot 3 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_13 SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_3 + +/* SAI peripheral configuration defines */ +#define AUDIO_SAIx SAI2_Block_B +#define AUDIO_SAIx_CLK_ENABLE() __HAL_RCC_SAI2_CLK_ENABLE() +#define AUDIO_SAIx_CLK_DISABLE() __HAL_RCC_SAI2_CLK_DISABLE() +#define AUDIO_SAIx_SCK_AF GPIO_AF8_SAI2 +#define AUDIO_SAIx_FS_SD_MCLK_AF GPIO_AF10_SAI2 + +#define AUDIO_SAIx_MCLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() +#define AUDIO_SAIx_MCLK_GPIO_PORT GPIOE +#define AUDIO_SAIx_MCLK_PIN GPIO_PIN_6 +#define AUDIO_SAIx_SCK_SD_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define AUDIO_SAIx_SCK_SD_GPIO_PORT GPIOA +#define AUDIO_SAIx_SCK_PIN GPIO_PIN_2 +#define AUDIO_SAIx_SD_PIN GPIO_PIN_0 +#define AUDIO_SAIx_FS_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE() +#define AUDIO_SAIx_FS_GPIO_PORT GPIOG +#define AUDIO_SAIx_FS_PIN GPIO_PIN_9 + + +/* SAI DMA Stream definitions */ +#define AUDIO_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_SAIx_DMAx_STREAM DMA2_Stream6 +#define AUDIO_SAIx_DMAx_CHANNEL DMA_CHANNEL_3 +#define AUDIO_SAIx_DMAx_IRQ DMA2_Stream6_IRQn +#define AUDIO_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD +#define AUDIO_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD +#define DMA_MAX_SZE 0xFFFF + +#define AUDIO_SAIx_DMAx_IRQHandler DMA2_Stream6_IRQHandler + +/* Select the interrupt preemption priority for the DMA interrupt */ +#define AUDIO_OUT_IRQ_PREPRIO ((uint32_t)0x0E) /* Select the preemption priority level(0 is the highest) */ + +/*------------------------------------------------------------------------------ + AUDIO IN CONFIGURATION +------------------------------------------------------------------------------*/ +/* SPI Configuration defines */ +#define AUDIO_I2Sx SPI3 +#define AUDIO_I2Sx_CLK_ENABLE() __HAL_RCC_SPI3_CLK_ENABLE() +#define AUDIO_I2Sx_CLK_DISABLE() __HAL_RCC_SPI3_CLK_DISABLE() +#define AUDIO_I2Sx_SCK_PIN GPIO_PIN_3 +#define AUDIO_I2Sx_SCK_GPIO_PORT GPIOB +#define AUDIO_I2Sx_SCK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define AUDIO_I2Sx_SCK_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE() +#define AUDIO_I2Sx_SCK_AF GPIO_AF6_SPI3 + +#define AUDIO_I2Sx_SD_PIN GPIO_PIN_6 +#define AUDIO_I2Sx_SD_GPIO_PORT GPIOD +#define AUDIO_I2Sx_SD_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() +#define AUDIO_I2Sx_SD_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE() +#define AUDIO_I2Sx_SD_AF GPIO_AF5_SPI3 + +/* I2S DMA Stream Rx definitions */ +#define AUDIO_I2Sx_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE() +#define AUDIO_I2Sx_DMAx_CLK_DISABLE() __HAL_RCC_DMA1_CLK_DISABLE() +#define AUDIO_I2Sx_DMAx_STREAM DMA1_Stream2 +#define AUDIO_I2Sx_DMAx_CHANNEL DMA_CHANNEL_0 +#define AUDIO_I2Sx_DMAx_IRQ DMA1_Stream2_IRQn +#define AUDIO_I2Sx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD +#define AUDIO_I2Sx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD + +#define AUDIO_I2Sx_DMAx_IRQHandler DMA1_Stream2_IRQHandler + +/* Select the interrupt preemption priority and subpriority for the IT/DMA interrupt */ +#define AUDIO_IN_IRQ_PREPRIO ((uint32_t)0x0F) /* Select the preemption priority level(0 is the highest) */ + + +/* Two channels are used: + - one channel as input which is connected to I2S SCK in stereo mode + - one channel as outupt which divides the frequency on the input +*/ + +#define AUDIO_TIMx_CLK_ENABLE() __HAL_RCC_TIM3_CLK_ENABLE() +#define AUDIO_TIMx_CLK_DISABLE() __HAL_RCC_TIM3_CLK_DISABLE() +#define AUDIO_TIMx TIM3 +#define AUDIO_TIMx_IN_CHANNEL TIM_CHANNEL_1 +#define AUDIO_TIMx_OUT_CHANNEL TIM_CHANNEL_2 /* Select channel 2 as output */ +#define AUDIO_TIMx_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define AUDIO_TIMx_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE() +#define AUDIO_TIMx_GPIO_PORT GPIOC +#define AUDIO_TIMx_IN_GPIO_PIN GPIO_PIN_6 +#define AUDIO_TIMx_OUT_GPIO_PIN GPIO_PIN_7 +#define AUDIO_TIMx_AF GPIO_AF2_TIM3 + +/*------------------------------------------------------------------------------ + CONFIGURATION: Audio Driver Configuration parameters +------------------------------------------------------------------------------*/ + +#define AUDIODATA_SIZE 2 /* 16-bits audio data size */ + +/* Audio status definition */ +#define AUDIO_OK ((uint8_t)0) +#define AUDIO_ERROR ((uint8_t)1) +#define AUDIO_TIMEOUT ((uint8_t)2) + +/* AudioFreq * DataSize (2 bytes) * NumChannels (Stereo: 2) */ +#define DEFAULT_AUDIO_IN_FREQ I2S_AUDIOFREQ_16K +#define DEFAULT_AUDIO_IN_BIT_RESOLUTION ((uint8_t)16) +#define DEFAULT_AUDIO_IN_CHANNEL_NBR ((uint8_t)2) /* Mono = 1, Stereo = 2 */ +#define DEFAULT_AUDIO_IN_VOLUME ((uint16_t)64) + +/* PDM buffer input size */ +#define INTERNAL_BUFF_SIZE (128*DEFAULT_AUDIO_IN_FREQ/16000*DEFAULT_AUDIO_IN_CHANNEL_NBR) +/* PCM buffer output size */ +#define PCM_OUT_SIZE (DEFAULT_AUDIO_IN_FREQ/1000*2) +#define CHANNEL_DEMUX_MASK ((uint8_t)0x55) + +/*------------------------------------------------------------------------------ + OPTIONAL Configuration defines parameters +------------------------------------------------------------------------------*/ + +/* Delay for the Codec to be correctly reset */ +#define CODEC_RESET_DELAY ((uint8_t)5) + + +/*------------------------------------------------------------------------------ + OUTPUT DEVICES definition +------------------------------------------------------------------------------*/ +/* Alias on existing output devices to adapt for 2 headphones output */ +#define OUTPUT_DEVICE_HEADPHONE1 OUTPUT_DEVICE_HEADPHONE +#define OUTPUT_DEVICE_HEADPHONE2 OUTPUT_DEVICE_SPEAKER /* Headphone2 is connected to Speaker output of the wm8994 */ + +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_AUDIO_Exported_Variables STM32756G_EVAL_AUDIO Exported Variables + * @{ + */ +extern __IO uint16_t AudioInVolume; + /** + * @} + */ + +/** @defgroup STM32756G_EVAL_AUDIO_Exported_Macros STM32756G_EVAL_AUDIO Exported Macros + * @{ + */ +#define DMA_MAX(x) (((x) <= DMA_MAX_SZE)? (x):DMA_MAX_SZE) +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_AUDIO_OUT_Exported_Functions STM32756G_EVAL_AUDIO_OUT Exported Functions + * @{ + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq); +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size); +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size); +uint8_t BSP_AUDIO_OUT_Pause(void); +uint8_t BSP_AUDIO_OUT_Resume(void); +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option); +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume); +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq); +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot); +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd); +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output); +void BSP_AUDIO_OUT_DeInit(void); + +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function is called when the requested data has been completely transferred.*/ +void BSP_AUDIO_OUT_TransferComplete_CallBack(void); + +/* This function is called when half of the requested buffer has been transferred. */ +void BSP_AUDIO_OUT_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_OUT_Error_CallBack(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params); +void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params); +void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); + +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_AUDIO_IN_Exported_Functions STM32756G_EVAL_AUDIO_IN Exported Functions + * @{ + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_Record(uint16_t *pData, uint32_t Size); +uint8_t BSP_AUDIO_IN_Stop(void); +uint8_t BSP_AUDIO_IN_Pause(void); +uint8_t BSP_AUDIO_IN_Resume(void); +uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume); +void BSP_AUDIO_IN_DeInit(void); +uint8_t BSP_AUDIO_IN_PDMToPCM(uint16_t* PDMBuf, uint16_t* PCMBuf); +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled to prepare the next + buffer pointer and its size. */ +void BSP_AUDIO_IN_TransferComplete_CallBack(void); +void BSP_AUDIO_IN_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_IN_Error_Callback(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_IN_MspInit(I2S_HandleTypeDef *hi2s, void *Params); +void BSP_AUDIO_IN_MspDeInit(I2S_HandleTypeDef *hi2s, void *Params); +void BSP_AUDIO_IN_ClockConfig(I2S_HandleTypeDef *hi2s, uint32_t AudioFreq, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32756G_EVAL_AUDIO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_camera.c b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_camera.c new file mode 100644 index 00000000..929e9009 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_camera.c @@ -0,0 +1,664 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_camera.c + * @author MCD Application Team + * @brief This file includes the driver for Camera modules mounted on + * STM32756G-EVAL and STM32746G-EVAL evaluation boards. + @verbatim + How to use this driver: + ----------------------- + - This driver is used to drive the camera. + - The S5K5CAG component driver MUST be included with this driver. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the camera using the BSP_CAMERA_Init() function. + o Start the camera capture/snapshot using the CAMERA_Start() function. + o Suspend, resume or stop the camera capture using the following functions: + - BSP_CAMERA_Suspend() + - BSP_CAMERA_Resume() + - BSP_CAMERA_Stop() + + + Options + o Increase or decrease on the fly the brightness and/or contrast + using the following function: + - BSP_CAMERA_ContrastBrightnessConfig + o Add a special effect on the fly using the following functions: + - BSP_CAMERA_BlackWhiteConfig() + - BSP_CAMERA_ColorEffectConfig() + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32756g_eval.c +- stm32f7xx_hal_dcmi.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- s5k5cag.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval_camera.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @defgroup STM32756G_EVAL_CAMERA STM32756G_EVAL CAMERA + * @{ + */ + +/** @defgroup STM32756G_EVAL_CAMERA_Private_TypesDefinitions CAMERA Private TypesDefinitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_CAMERA_Private_Defines CAMERA Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_CAMERA_Private_Macros CAMERA Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_CAMERA_Private_Variables CAMERA Private Variables + * @{ + */ +DCMI_HandleTypeDef hDcmiEval; +CAMERA_DrvTypeDef *camera_drv; +/* Camera current resolution naming (QQVGA, VGA, ...) */ +static uint32_t CameraCurrentResolution; + +/* Camera module I2C HW address */ +static uint32_t CameraHwAddress; +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_CAMERA_Private_FunctionsPrototypes CAMERA Private Functions Prototypes + * @{ + */ +static uint32_t GetSize(uint32_t resolution); +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_CAMERA_Private_Functions CAMERA Private Functions + * @{ + */ + +/** + * @brief Initializes the camera. + * @param Resolution : camera sensor requested resolution (x, y) : standard resolution + * naming QQVGA, QVGA, VGA ... + * + * @retval Camera status + */ +uint8_t BSP_CAMERA_Init(uint32_t Resolution) +{ + DCMI_HandleTypeDef *phdcmi; + uint8_t status = CAMERA_ERROR; + + /* Get the DCMI handle structure */ + phdcmi = &hDcmiEval; + + /*** Configures the DCMI to interface with the camera module ***/ + /* DCMI configuration */ + phdcmi->Init.CaptureRate = DCMI_CR_ALL_FRAME; + phdcmi->Init.HSPolarity = DCMI_HSPOLARITY_HIGH; + phdcmi->Init.SynchroMode = DCMI_SYNCHRO_HARDWARE; + phdcmi->Init.VSPolarity = DCMI_VSPOLARITY_HIGH; + phdcmi->Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B; + phdcmi->Init.PCKPolarity = DCMI_PCKPOLARITY_RISING; + phdcmi->Instance = DCMI; + + /* Configure IO functionalities for CAMERA detect pin */ + BSP_IO_Init(); + + /* Apply Camera Module hardware reset */ + BSP_CAMERA_HwReset(); + + /* Check if the CAMERA Module is plugged on board */ + if(BSP_IO_ReadPin(CAM_PLUG_PIN) == BSP_IO_PIN_SET) + { + status = CAMERA_NOT_DETECTED; + return status; /* Exit with error */ + } + + /* Read ID of Camera module via I2C */ + if (s5k5cag_ReadID(CAMERA_I2C_ADDRESS) == S5K5CAG_ID) + { + /* Initialize the camera driver structure */ + camera_drv = &s5k5cag_drv; + CameraHwAddress = CAMERA_I2C_ADDRESS; + + /* DCMI Initialization */ + BSP_CAMERA_MspInit(&hDcmiEval, NULL); + HAL_DCMI_Init(phdcmi); + + /* Camera Module Initialization via I2C to the wanted 'Resolution' */ + camera_drv->Init(CameraHwAddress, Resolution); + + CameraCurrentResolution = Resolution; + + /* Return CAMERA_OK status */ + status = CAMERA_OK; + } + else if(ov5640_ReadID(CAMERA_I2C_ADDRESS_2) == OV5640_ID) + { + /* Initialize the camera driver structure */ + camera_drv = &ov5640_drv; + CameraHwAddress = CAMERA_I2C_ADDRESS_2; + + /* DCMI Initialization */ + BSP_CAMERA_MspInit(&hDcmiEval, NULL); + HAL_DCMI_Init(phdcmi); + + /* Camera Module Initialization via I2C to the wanted 'Resolution' */ + camera_drv->Init(CameraHwAddress, Resolution); + + CameraCurrentResolution = Resolution; + + /* Return CAMERA_OK status */ + status = CAMERA_OK; + } + else + { + /* Return CAMERA_NOT_SUPPORTED status */ + status = CAMERA_NOT_SUPPORTED; + } + + return status; +} + +/** + * @brief DeInitializes the camera. + * @retval Camera status + */ +uint8_t BSP_CAMERA_DeInit(void) +{ + hDcmiEval.Instance = DCMI; + + HAL_DCMI_DeInit(&hDcmiEval); + BSP_CAMERA_MspDeInit(&hDcmiEval, NULL); + return CAMERA_OK; +} + +/** + * @brief Starts the camera capture in continuous mode. + * @param buff: pointer to the camera output buffer + * @retval None + */ +void BSP_CAMERA_ContinuousStart(uint8_t *buff) +{ + /* Start the camera capture */ + HAL_DCMI_Start_DMA(&hDcmiEval, DCMI_MODE_CONTINUOUS, (uint32_t)buff, GetSize(CameraCurrentResolution)); +} + +/** + * @brief Starts the camera capture in snapshot mode. + * @param buff: pointer to the camera output buffer + * @retval None + */ +void BSP_CAMERA_SnapshotStart(uint8_t *buff) +{ + /* Start the camera capture */ + HAL_DCMI_Start_DMA(&hDcmiEval, DCMI_MODE_SNAPSHOT, (uint32_t)buff, GetSize(CameraCurrentResolution)); +} + +/** + * @brief Suspend the CAMERA capture + + * @retval None + */ +void BSP_CAMERA_Suspend(void) +{ + /* Suspend the Camera Capture */ + HAL_DCMI_Suspend(&hDcmiEval); +} + +/** + * @brief Resume the CAMERA capture + * @retval None + */ +void BSP_CAMERA_Resume(void) +{ + /* Start the Camera Capture */ + HAL_DCMI_Resume(&hDcmiEval); +} + +/** + * @brief Stop the CAMERA capture + * @retval Camera status + */ +uint8_t BSP_CAMERA_Stop(void) +{ + uint8_t status = CAMERA_ERROR; + + if(HAL_DCMI_Stop(&hDcmiEval) == HAL_OK) + { + status = CAMERA_OK; + } + + /* Set Camera in Power Down */ + BSP_CAMERA_PwrDown(); + + return status; +} + +/** + * @brief CANERA hardware reset + * @retval None + */ +void BSP_CAMERA_HwReset(void) +{ + /* Camera sensor RESET sequence */ + BSP_IO_ConfigPin(RSTI_PIN, IO_MODE_OUTPUT); + BSP_IO_ConfigPin(XSDN_PIN, IO_MODE_OUTPUT); + + /* Assert the camera STANDBY pin (active high) */ + BSP_IO_WritePin(XSDN_PIN, BSP_IO_PIN_SET); + + /* Assert the camera RSTI pin (active low) */ + BSP_IO_WritePin(RSTI_PIN, BSP_IO_PIN_RESET); + + HAL_Delay(100); /* RST and XSDN signals asserted during 100ms */ + + /* De-assert the camera STANDBY pin (active high) */ + BSP_IO_WritePin(XSDN_PIN, BSP_IO_PIN_RESET); + + HAL_Delay(3); /* RST de-asserted and XSDN asserted during 3ms */ + + /* De-assert the camera RSTI pin (active low) */ + BSP_IO_WritePin(RSTI_PIN, BSP_IO_PIN_SET); + + HAL_Delay(6); /* RST de-asserted during 3ms */ +} + +/** + * @brief CAMERA power down + * @retval None + */ +void BSP_CAMERA_PwrDown(void) +{ + /* Camera power down sequence */ + BSP_IO_ConfigPin(RSTI_PIN, IO_MODE_OUTPUT); + BSP_IO_ConfigPin(XSDN_PIN, IO_MODE_OUTPUT); + + /* De-assert the camera STANDBY pin (active high) */ + BSP_IO_WritePin(XSDN_PIN, BSP_IO_PIN_RESET); + + /* Assert the camera RSTI pin (active low) */ + BSP_IO_WritePin(RSTI_PIN, BSP_IO_PIN_RESET); +} + +/** + * @brief Configures the camera contrast and brightness. + * @param contrast_level: Contrast level + * This parameter can be one of the following values: + * @arg CAMERA_CONTRAST_LEVEL4: for contrast +2 + * @arg CAMERA_CONTRAST_LEVEL3: for contrast +1 + * @arg CAMERA_CONTRAST_LEVEL2: for contrast 0 + * @arg CAMERA_CONTRAST_LEVEL1: for contrast -1 + * @arg CAMERA_CONTRAST_LEVEL0: for contrast -2 + * @param brightness_level: Contrast level + * This parameter can be one of the following values: + * @arg CAMERA_BRIGHTNESS_LEVEL4: for brightness +2 + * @arg CAMERA_BRIGHTNESS_LEVEL3: for brightness +1 + * @arg CAMERA_BRIGHTNESS_LEVEL2: for brightness 0 + * @arg CAMERA_BRIGHTNESS_LEVEL1: for brightness -1 + * @arg CAMERA_BRIGHTNESS_LEVEL0: for brightness -2 + * @retval None + */ +void BSP_CAMERA_ContrastBrightnessConfig(uint32_t contrast_level, uint32_t brightness_level) +{ + if(camera_drv->Config != NULL) + { + camera_drv->Config(CameraHwAddress, CAMERA_CONTRAST_BRIGHTNESS, contrast_level, brightness_level); + } +} + +/** + * @brief Configures the camera white balance. + * @param Mode: black_white mode + * This parameter can be one of the following values: + * @arg CAMERA_BLACK_WHITE_BW + * @arg CAMERA_BLACK_WHITE_NEGATIVE + * @arg CAMERA_BLACK_WHITE_BW_NEGATIVE + * @arg CAMERA_BLACK_WHITE_NORMAL + * @retval None + */ +void BSP_CAMERA_BlackWhiteConfig(uint32_t Mode) +{ + if(camera_drv->Config != NULL) + { + camera_drv->Config(CameraHwAddress, CAMERA_BLACK_WHITE, Mode, 0); + } +} + +/** + * @brief Configures the camera color effect. + * @param Effect: Color effect + * This parameter can be one of the following values: + * @arg CAMERA_COLOR_EFFECT_ANTIQUE + * @arg CAMERA_COLOR_EFFECT_BLUE + * @arg CAMERA_COLOR_EFFECT_GREEN + * @arg CAMERA_COLOR_EFFECT_RED + * @retval None + */ +void BSP_CAMERA_ColorEffectConfig(uint32_t Effect) +{ + if(camera_drv->Config != NULL) + { + camera_drv->Config(CameraHwAddress, CAMERA_COLOR_EFFECT, Effect, 0); + } +} + +/** + * @brief Get the capture size in pixels unit. + * @param resolution: the current resolution. + * @retval capture size in pixels unit. + */ +static uint32_t GetSize(uint32_t resolution) +{ + uint32_t size = 0; + + /* Get capture size */ + switch (resolution) + { + case CAMERA_R160x120: + { + size = 0x2580; + } + break; + case CAMERA_R320x240: + { + size = 0x9600; + } + break; + case CAMERA_R480x272: + { + size = 0xFF00; + } + break; + case CAMERA_R640x480: + { + size = 0x25800; + } + break; + default: + { + break; + } + } + + return size; +} + +/** + * @brief Initializes the DCMI MSP. + * @param hdcmi: pointer to the DCMI handle + * @param Params + * @retval None + */ +__weak void BSP_CAMERA_MspInit(DCMI_HandleTypeDef *hdcmi, void *Params) +{ + static DMA_HandleTypeDef hdma_eval; + GPIO_InitTypeDef gpio_init_structure; + + /*** Enable peripherals and GPIO clocks ***/ + /* Enable DCMI clock */ + __HAL_RCC_DCMI_CLK_ENABLE(); + + /* Enable DMA2 clock */ + __HAL_RCC_DMA2_CLK_ENABLE(); + + /* Enable GPIO clocks */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + + /*** Configure the GPIO ***/ + /* Configure DCMI GPIO as alternate function */ + /* On STM32756G-EVAL RevB, to use camera, ensure that JP23 is in position 1-2, + * LED3 is then no more usable */ + gpio_init_structure.Pin = GPIO_PIN_4 | GPIO_PIN_6; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOA, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_7; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOB, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 |\ + GPIO_PIN_9 | GPIO_PIN_11; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOC, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_3 | GPIO_PIN_6; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_5 | GPIO_PIN_6; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /*** Configure the DMA ***/ + /* Set the parameters to be configured */ + hdma_eval.Init.Channel = DMA_CHANNEL_1; + hdma_eval.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_eval.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_eval.Init.MemInc = DMA_MINC_ENABLE; + hdma_eval.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + hdma_eval.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + hdma_eval.Init.Mode = DMA_CIRCULAR; + hdma_eval.Init.Priority = DMA_PRIORITY_HIGH; + hdma_eval.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_eval.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_eval.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_eval.Init.PeriphBurst = DMA_PBURST_SINGLE; + + hdma_eval.Instance = DMA2_Stream1; + + /* Associate the initialized DMA handle to the DCMI handle */ + __HAL_LINKDMA(hdcmi, DMA_Handle, hdma_eval); + + /*** Configure the NVIC for DCMI and DMA ***/ + /* NVIC configuration for DCMI transfer complete interrupt */ + HAL_NVIC_SetPriority(DCMI_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DCMI_IRQn); + + /* NVIC configuration for DMA2D transfer complete interrupt */ + HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn); + + /* Configure the DMA stream */ + HAL_DMA_Init(hdcmi->DMA_Handle); +} + + +/** + * @brief DeInitializes the DCMI MSP. + * @param hdcmi: pointer to the DCMI handle + * @param Params + * @retval None + */ +__weak void BSP_CAMERA_MspDeInit(DCMI_HandleTypeDef *hdcmi, void *Params) +{ + /* Disable NVIC for DCMI transfer complete interrupt */ + HAL_NVIC_DisableIRQ(DCMI_IRQn); + + /* Disable NVIC for DMA2 transfer complete interrupt */ + HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn); + + /* Configure the DMA stream */ + HAL_DMA_DeInit(hdcmi->DMA_Handle); + + /* Disable DCMI clock */ + __HAL_RCC_DCMI_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Line event callback + * @param hdcmi: pointer to the DCMI handle + * @retval None + */ +void HAL_DCMI_LineEventCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_LineEventCallback(); +} + +/** + * @brief Line Event callback. + * @retval None + */ +__weak void BSP_CAMERA_LineEventCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_LineEventCallback could be implemented in the user file + */ +} + +/** + * @brief VSYNC event callback + * @param hdcmi: pointer to the DCMI handle + * @retval None + */ +void HAL_DCMI_VsyncEventCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_VsyncEventCallback(); +} + +/** + * @brief VSYNC Event callback. + * @retval None + */ +__weak void BSP_CAMERA_VsyncEventCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_VsyncEventCallback could be implemented in the user file + */ +} + +/** + * @brief Frame event callback + * @param hdcmi: pointer to the DCMI handle + * @retval None + */ +void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_FrameEventCallback(); +} + +/** + * @brief Frame Event callback. + * @retval None + */ +__weak void BSP_CAMERA_FrameEventCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_FrameEventCallback could be implemented in the user file + */ +} + +/** + * @brief Error callback + * @param hdcmi: pointer to the DCMI handle + * @retval None + */ +void HAL_DCMI_ErrorCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_ErrorCallback(); +} + +/** + * @brief Error callback. + * @retval None + */ +__weak void BSP_CAMERA_ErrorCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_ErrorCallback could be implemented in the user file + */ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_camera.h b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_camera.h new file mode 100644 index 00000000..3fdf2567 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_camera.h @@ -0,0 +1,154 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_camera.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32756g_eval_camera.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32756G_EVAL_CAMERA_H +#define __STM32756G_EVAL_CAMERA_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include Camera component Driver */ +#include "../Components/s5k5cag/s5k5cag.h" +#include "../Components/ov5640/ov5640.h" + +/* Include IO Driver */ +#include "stm32756g_eval_io.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @addtogroup STM32756G_EVAL_CAMERA + * @{ + */ + +/** @defgroup STM32756G_EVAL_CAMERA_Exported_Types CAMERA Exported Types + * @{ + */ + +/** + * @brief Camera State structures definition + */ +typedef enum +{ + CAMERA_OK = 0x00, + CAMERA_ERROR = 0x01, + CAMERA_TIMEOUT = 0x02, + CAMERA_NOT_DETECTED = 0x03, + CAMERA_NOT_SUPPORTED = 0x04 + +} Camera_StatusTypeDef; + +#define RESOLUTION_R160x120 CAMERA_R160x120 /* QQVGA Resolution */ +#define RESOLUTION_R320x240 CAMERA_R320x240 /* QVGA Resolution */ +#define RESOLUTION_R480x272 CAMERA_R480x272 /* 480x272 Resolution */ +#define RESOLUTION_R640x480 CAMERA_R640x480 /* VGA Resolution */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_CAMERA_Exported_Constants CAMERA Exported Constants + * @{ + */ +#define BSP_CAMERA_IRQHandler DCMI_IRQHandler +#define BSP_CAMERA_DMA_IRQHandler DMA2_Stream1_IRQHandler +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_CAMERA_Exported_Functions CAMERA Exported Functions + * @{ + */ +uint8_t BSP_CAMERA_Init(uint32_t Resolution); +uint8_t BSP_CAMERA_DeInit(void); +void BSP_CAMERA_ContinuousStart(uint8_t *buff); +void BSP_CAMERA_SnapshotStart(uint8_t *buff); +void BSP_CAMERA_Suspend(void); +void BSP_CAMERA_Resume(void); +uint8_t BSP_CAMERA_Stop(void); +void BSP_CAMERA_HwReset(void); +void BSP_CAMERA_PwrDown(void); +void BSP_CAMERA_LineEventCallback(void); +void BSP_CAMERA_VsyncEventCallback(void); +void BSP_CAMERA_FrameEventCallback(void); +void BSP_CAMERA_ErrorCallback(void); + +/* Camera features functions prototype */ +void BSP_CAMERA_ContrastBrightnessConfig(uint32_t contrast_level, uint32_t brightness_level); +void BSP_CAMERA_BlackWhiteConfig(uint32_t Mode); +void BSP_CAMERA_ColorEffectConfig(uint32_t Effect); + +/* To be called in DCMI_IRQHandler function */ +void BSP_CAMERA_IRQHandler(void); +/* To be called in DMA2_Stream1_IRQHandler function */ +void BSP_CAMERA_DMA_IRQHandler(void); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_CAMERA_MspInit(DCMI_HandleTypeDef *hdcmi, void *Params); +void BSP_CAMERA_MspDeInit(DCMI_HandleTypeDef *hdcmi, void *Params); + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32756G_EVAL_CAMERA_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_eeprom.c b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_eeprom.c new file mode 100644 index 00000000..30f7ff15 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_eeprom.c @@ -0,0 +1,476 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_eeprom.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage an I2C M24LR64 + * EEPROM memory. + @verbatim + To be able to use this driver, the switch EE_M24LR64 must be defined + in your toolchain compiler preprocessor + + =================================================================== + Notes: + - The I2C EEPROM memory (M24LR64) is available on separate daughter + board ANT7-M24LR-A, which is not provided with the STM32756G_EVAL + and STM32746G_EVAL boards. + To use this driver you have to connect the ANT7-M24LR-A to CN2 + connector of STM32756G_EVAL board. + =================================================================== + + It implements a high level communication layer for read and write + from/to this memory. The needed STM32F7xx hardware resources (I2C and + GPIO) are defined in stm32756g_eval.h file, and the initialization is + performed in EEPROM_IO_Init() function declared in stm32756g_eval.c + file. + You can easily tailor this driver to any other development board, + by just adapting the defines for hardware resources and + EEPROM_IO_Init() function. + + @note In this driver, basic read and write functions (BSP_EEPROM_ReadBuffer() + and BSP_EEPROM_WritePage()) use DMA mode to perform the data + transfer to/from EEPROM memory. + + @note Regarding BSP_EEPROM_WritePage(), it is an optimized function to perform + small write (less than 1 page) BUT the number of bytes (combined to write start address) must not + cross the EEPROM page boundary. This function can only writes into + the boundaries of an EEPROM page. + This function doesn't check on boundaries condition (in this driver + the function BSP_EEPROM_WriteBuffer() which calls BSP_EEPROM_WritePage() is + responsible of checking on Page boundaries). + + + +-----------------------------------------------------------------+ + | Pin assignment for M24LR64 EEPROM | + +---------------------------------------+-----------+-------------+ + | STM32F7xx I2C Pins | EEPROM | Pin | + +---------------------------------------+-----------+-------------+ + | . | E0(GND) | 1 (0V) | + | . | AC0 | 2 | + | . | AC1 | 3 | + | . | VSS | 4 (0V) | + | SDA | SDA | 5 | + | SCL | SCL | 6 | + | . | E1(GND) | 7 (0V) | + | . | VDD | 8 (3.3V) | + +---------------------------------------+-----------+-------------+ + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32756g_eval.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval_eeprom.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @defgroup STM32756G_EVAL_EEPROM STM32756G_EVAL EEPROM + * @brief This file includes the I2C EEPROM driver of STM32756G-EVAL evaluation board. + * @{ + */ + +/** @defgroup STM32756G_EVAL_EEPROM_Private_Types EEPROM Private Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_EEPROM_Private_Defines EEPROM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_EEPROM_Private_Macros EEPROM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_EEPROM_Private_Variables EEPROM Private Variables + * @{ + */ +__IO uint16_t EEPROMAddress = 0; +__IO uint16_t EEPROMDataRead; +__IO uint8_t EEPROMDataWrite; +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_EEPROM_Private_Functions_Prototypes EEPROM Private Functions Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_EEPROM_Private_Functions EEPROM Private Functions + * @{ + */ + +/** + * @brief Initializes peripherals used by the I2C EEPROM driver. + * @note There are 2 different versions of M24LR64 (A01 & A02). + * Then try to connect on 1st one (EEPROM_I2C_ADDRESS_A01) + * and if problem, check the 2nd one (EEPROM_I2C_ADDRESS_A02) + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) + */ +uint32_t BSP_EEPROM_Init(void) +{ + /* I2C Initialization */ + EEPROM_IO_Init(); + + /* Select the EEPROM address for A01 and check if OK */ + EEPROMAddress = EEPROM_I2C_ADDRESS_A01; + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + /* Select the EEPROM address for A02 and check if OK */ + EEPROMAddress = EEPROM_I2C_ADDRESS_A02; + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + return EEPROM_FAIL; + } + } + return EEPROM_OK; +} + +/** + * @brief DeInitializes the EEPROM. + * @retval EEPROM state + */ +uint8_t BSP_EEPROM_DeInit(void) +{ + /* I2C won't be disabled because common to other functionalities */ + return EEPROM_OK; +} + +/** + * @brief Reads a block of data from the EEPROM. + * @param pBuffer: pointer to the buffer that receives the data read from + * the EEPROM. + * @param ReadAddr: EEPROM's internal address to start reading from. + * @param NumByteToRead: pointer to the variable holding number of bytes to + * be read from the EEPROM. + * + * @note The variable pointed by NumByteToRead is reset to 0 when all the + * data are read from the EEPROM. Application should monitor this + * variable in order know when the transfer is complete. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead) +{ + uint32_t buffersize = *NumByteToRead; + + /* Set the pointer to the Number of data to be read. This pointer will be used + by the DMA Transfer Completer interrupt Handler in order to reset the + variable to 0. User should check on this variable in order to know if the + DMA transfer has been complete or not. */ + EEPROMDataRead = *NumByteToRead; + + if(EEPROM_IO_ReadData(EEPROMAddress, ReadAddr, pBuffer, buffersize) != HAL_OK) + { + BSP_EEPROM_TIMEOUT_UserCallback(); + return EEPROM_FAIL; + } + + /* If all operations OK, return EEPROM_OK (0) */ + return EEPROM_OK; +} + +/** + * @brief Writes more than one byte to the EEPROM with a single WRITE cycle. + * + * @note The number of bytes (combined to write start address) must not + * cross the EEPROM page boundary. This function can only write into + * the boundaries of an EEPROM page. + * This function doesn't check on boundaries condition (in this driver + * the function BSP_EEPROM_WriteBuffer() which calls BSP_EEPROM_WritePage() is + * responsible of checking on Page boundaries). + * + * @param pBuffer: pointer to the buffer containing the data to be written to + * the EEPROM. + * @param WriteAddr: EEPROM's internal address to write to. + * @param NumByteToWrite: pointer to the variable holding number of bytes to + * be written into the EEPROM. + * + * @note The variable pointed by NumByteToWrite is reset to 0 when all the + * data are written to the EEPROM. Application should monitor this + * variable in order know when the transfer is complete. + * + * @note This function just configure the communication and enable the DMA + * channel to transfer data. Meanwhile, the user application may perform + * other tasks in parallel. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite) +{ + uint32_t buffersize = *NumByteToWrite; + uint32_t status = EEPROM_OK; + + /* Set the pointer to the Number of data to be written. This pointer will be used + by the DMA Transfer Completer interrupt Handler in order to reset the + variable to 0. User should check on this variable in order to know if the + DMA transfer has been complete or not. */ + EEPROMDataWrite = *NumByteToWrite; + + if(EEPROM_IO_WriteData(EEPROMAddress, WriteAddr, pBuffer, buffersize) != HAL_OK) + { + BSP_EEPROM_TIMEOUT_UserCallback(); + status = EEPROM_FAIL; + } + + if(BSP_EEPROM_WaitEepromStandbyState() != EEPROM_OK) + { + return EEPROM_FAIL; + } + + /* If all operations OK, return EEPROM_OK (0) */ + return status; +} + +/** + * @brief Writes buffer of data to the I2C EEPROM. + * @param pBuffer: pointer to the buffer containing the data to be written + * to the EEPROM. + * @param WriteAddr: EEPROM's internal address to write to. + * @param NumByteToWrite: number of bytes to write to the EEPROM. + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WriteBuffer(uint8_t *pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite) +{ + uint16_t numofpage = 0, numofsingle = 0, count = 0; + uint16_t addr = 0; + uint8_t dataindex = 0; + uint32_t status = EEPROM_OK; + + addr = WriteAddr % EEPROM_PAGESIZE; + count = EEPROM_PAGESIZE - addr; + numofpage = NumByteToWrite / EEPROM_PAGESIZE; + numofsingle = NumByteToWrite % EEPROM_PAGESIZE; + + /* If WriteAddr is EEPROM_PAGESIZE aligned */ + if(addr == 0) + { + /* If NumByteToWrite < EEPROM_PAGESIZE */ + if(numofpage == 0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + /* Start writing data */ + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + /* If NumByteToWrite > EEPROM_PAGESIZE */ + else + { + while(numofpage--) + { + /* Store the number of data to be written */ + dataindex = EEPROM_PAGESIZE; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + + WriteAddr += EEPROM_PAGESIZE; + pBuffer += EEPROM_PAGESIZE; + } + + if(numofsingle!=0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + } + /* If WriteAddr is not EEPROM_PAGESIZE aligned */ + else + { + /* If NumByteToWrite < EEPROM_PAGESIZE */ + if(numofpage== 0) + { + /* If the number of data to be written is more than the remaining space + in the current page: */ + if(NumByteToWrite > count) + { + /* Store the number of data to be written */ + dataindex = count; + /* Write the data contained in same page */ + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + + /* Store the number of data to be written */ + dataindex = (NumByteToWrite - count); + /* Write the remaining data in the following page */ + status = BSP_EEPROM_WritePage((uint8_t*)(pBuffer + count), (WriteAddr + count), (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + else + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + /* If NumByteToWrite > EEPROM_PAGESIZE */ + else + { + NumByteToWrite -= count; + numofpage = NumByteToWrite / EEPROM_PAGESIZE; + numofsingle = NumByteToWrite % EEPROM_PAGESIZE; + + if(count != 0) + { + /* Store the number of data to be written */ + dataindex = count; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + WriteAddr += count; + pBuffer += count; + } + + while(numofpage--) + { + /* Store the number of data to be written */ + dataindex = EEPROM_PAGESIZE; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + WriteAddr += EEPROM_PAGESIZE; + pBuffer += EEPROM_PAGESIZE; + } + if(numofsingle != 0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + } + + /* If all operations OK, return EEPROM_OK (0) */ + return EEPROM_OK; +} + +/** + * @brief Wait for EEPROM Standby state. + * + * @note This function allows to wait and check that EEPROM has finished the + * last operation. It is mostly used after Write operation: after receiving + * the buffer to be written, the EEPROM may need additional time to actually + * perform the write operation. During this time, it doesn't answer to + * I2C packets addressed to it. Once the write operation is complete + * the EEPROM responds to its address. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WaitEepromStandbyState(void) +{ + /* Check if the maximum allowed number of trials has bee reached */ + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + /* If the maximum number of trials has been reached, exit the function */ + BSP_EEPROM_TIMEOUT_UserCallback(); + return EEPROM_TIMEOUT; + } + return EEPROM_OK; +} + +/** + * @brief Basic management of the timeout situation. + * @retval None + */ +__weak void BSP_EEPROM_TIMEOUT_UserCallback(void) +{ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_eeprom.h b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_eeprom.h new file mode 100644 index 00000000..ae4db005 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_eeprom.h @@ -0,0 +1,138 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_eeprom.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for + * the stm32756g_eval_eeprom.c firmware driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F756G_EVAL_EEPROM_H +#define __STM32F756G_EVAL_EEPROM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @addtogroup STM32756G_EVAL_EEPROM STM32756G_EVAL EEPROM + * @brief This file includes the I2C EEPROM driver of STM32756G-EVAL evaluation board. + * @{ + */ + +/** @defgroup STM32756G_EVAL_EEPROM_Exported_Types EEPROM Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_EEPROM_Exported_Constants EEPROM Exported Constants + * @{ + */ +/* EEPROM hardware address and page size */ +#define EEPROM_PAGESIZE ((uint8_t)4) +#define EEPROM_MAX_SIZE ((uint16_t)0x2000) /* 64Kbit */ + + +/* Maximum number of trials for EEPROM_WaitEepromStandbyState() function */ +#define EEPROM_MAX_TRIALS ((uint32_t)3000) + +#define EEPROM_OK ((uint32_t)0) +#define EEPROM_FAIL ((uint32_t)1) +#define EEPROM_TIMEOUT ((uint32_t)2) +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_EEPROM_Exported_Macros EEPROM Exported Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_EEPROM_Exported_Functions EEPROM Exported Functions + * @{ + */ +uint32_t BSP_EEPROM_Init(void); +uint8_t BSP_EEPROM_DeInit(void); +uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead); +uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite); +uint32_t BSP_EEPROM_WriteBuffer(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite); +uint32_t BSP_EEPROM_WaitEepromStandbyState(void); + +/* USER Callbacks: This function is declared as __weak in EEPROM driver and + should be implemented into user application. + BSP_EEPROM_TIMEOUT_UserCallback() function is called whenever a timeout condition + occurs during communication (waiting on an event that doesn't occur, bus + errors, busy devices ...). */ +void BSP_EEPROM_TIMEOUT_UserCallback(void); + +/* Link function for I2C EEPROM peripheral */ +void EEPROM_IO_Init(void); +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32756G_EVAL_EEPROM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_io.c b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_io.c new file mode 100644 index 00000000..d99545f2 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_io.c @@ -0,0 +1,325 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_io.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the IO pins + * on STM32756G-EVAL and STM32746G-EVAL evaluation board. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the IO module of the STM32756G-EVAL evaluation + board. + - The MFXSTM32L152 IO expander device component driver must be included with this + driver in order to run the IO functionalities commanded by the IO expander (MFX) + device mounted on the evaluation board. + + Driver description: + ------------------- + + Initialization steps: + o Initialize the IO module using the BSP_IO_Init() function. This + function includes the MSP layer hardware resources initialization and the + communication layer configuration to start the IO functionalities use. + + + IO functionalities use + o The IO pin mode is configured when calling the function BSP_IO_ConfigPin(), you + must specify the desired IO mode by choosing the "IO_ModeTypedef" parameter + predefined value. + o If an IO pin is used in interrupt mode, the function BSP_IO_ITGetStatus() is + needed to get the interrupt status. To clear the IT pending bits, you should + call the function BSP_IO_ITClear() with specifying the IO pending bit to clear. + o The IT is handled using the corresponding external interrupt IRQ handler, + the user IT callback treatment is implemented on the same external interrupt + callback. + o The IRQ_OUT pin (common for all functionalities: JOY, SD, LEDs, etc) can be + configured using the function BSP_IO_ConfigIrqOutPin() + o To get/set an IO pin combination state you can use the functions + BSP_IO_ReadPin()/BSP_IO_WritePin() or the function BSP_IO_TogglePin() to toggle the pin + state. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32756g_eval.h +- mfxstm32l152.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval_io.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @defgroup STM32756G_EVAL_IO STM32756G_EVAL IO + * @{ + */ + +/** @defgroup STM32756G_EVAL_IO_Private_Types_Definitions IO Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_IO_Private_Defines IO Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_IO_Private_Macros IO Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_IO_Private_Variables IO Private Variables + * @{ + */ +static IO_DrvTypeDef *IoDrv = NULL; +static uint8_t mfxstm32l152Identifier; + +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_IO_Private_Functions_Prototypes IO Private Functions Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_IO_Private_Functions IO Private Functions + * @{ + */ + +/** + * @brief Initializes and configures the IO functionalities and configures all + * necessary hardware resources (MFX, ...). + * @note BSP_IO_Init() is using HAL_Delay() function to ensure that MFXSTM32L152 + * IO Expander is correctly reset. HAL_Delay() function provides accurate + * delay (in milliseconds) based on variable incremented in SysTick ISR. + * This implies that if BSP_IO_Init() is called from a peripheral ISR process, + * then the SysTick interrupt must have higher priority (numerically lower) + * than the peripheral interrupt. Otherwise the caller ISR process will be blocked. + * @retval IO_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_IO_Init(void) +{ + uint8_t ret = IO_OK; + + if (IoDrv == NULL) /* Checks if MFX initialization never done */ + { + /* Read ID and verify the MFX is ready */ + mfxstm32l152Identifier = mfxstm32l152_io_drv.ReadID(IO_I2C_ADDRESS); + if((mfxstm32l152Identifier == MFXSTM32L152_ID_1) || (mfxstm32l152Identifier == MFXSTM32L152_ID_2)) + { + /* Initialize the IO driver structure */ + IoDrv = &mfxstm32l152_io_drv; + + /* Initialize MFX */ + IoDrv->Init(IO_I2C_ADDRESS); + IoDrv->Start(IO_I2C_ADDRESS, IO_PIN_ALL); + } + else + { + ret = IO_ERROR; + } + } + else + { + /* MFX initialization already done : do nothing */ + } + + return ret; +} + +/** + * @brief DeInit allows Mfx Initialization to be executed again + * @note BSP_IO_Init() has no effect if the IoDrv is already initialized + * BSP_IO_DeInit() allows to erase the pointer such to allow init to be effective + * @retval IO_OK + */ +uint8_t BSP_IO_DeInit(void) +{ + IoDrv = NULL; + return IO_OK; +} + +/** + * @brief Gets the selected pins IT status. + * @param IoPin: Selected pins to check the status. + * This parameter can be any combination of the IO pins. + * @retval IO_OK if read status OK. Other value if error. + */ +uint32_t BSP_IO_ITGetStatus(uint32_t IoPin) +{ + /* Return the IO Pin IT status */ + return (IoDrv->ITStatus(IO_I2C_ADDRESS, IoPin)); +} + +/** + * @brief Clears all the IO IT pending bits. + * @retval None + */ +void BSP_IO_ITClear(void) +{ + /* Clear all IO IT pending bits */ + IoDrv->ClearIT(IO_I2C_ADDRESS, MFXSTM32L152_GPIO_PINS_ALL); +} + +/** + * @brief Configures the IO pin(s) according to IO mode structure value. + * @param IoPin: IO pin(s) to be configured. + * This parameter can be one of the following values: + * @arg MFXSTM32L152_GPIO_PIN_x: where x can be from 0 to 23. + * @param IoMode: IO pin mode to configure + * This parameter can be one of the following values: + * @arg IO_MODE_INPUT + * @arg IO_MODE_OUTPUT + * @arg IO_MODE_IT_RISING_EDGE + * @arg IO_MODE_IT_FALLING_EDGE + * @arg IO_MODE_IT_LOW_LEVEL + * @arg IO_MODE_IT_HIGH_LEVEL + * @arg IO_MODE_ANALOG + * @arg IO_MODE_OFF + * @arg IO_MODE_INPUT_PU, + * @arg IO_MODE_INPUT_PD, + * @arg IO_MODE_OUTPUT_OD, + * @arg IO_MODE_OUTPUT_OD_PU, + * @arg IO_MODE_OUTPUT_OD_PD, + * @arg IO_MODE_OUTPUT_PP, + * @arg IO_MODE_OUTPUT_PP_PU, + * @arg IO_MODE_OUTPUT_PP_PD, + * @arg IO_MODE_IT_RISING_EDGE_PU + * @arg IO_MODE_IT_FALLING_EDGE_PU + * @arg IO_MODE_IT_LOW_LEVEL_PU + * @arg IO_MODE_IT_HIGH_LEVEL_PU + * @arg IO_MODE_IT_RISING_EDGE_PD + * @arg IO_MODE_IT_FALLING_EDGE_PD + * @arg IO_MODE_IT_LOW_LEVEL_PD + * @arg IO_MODE_IT_HIGH_LEVEL_PD + * @retval IO_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_IO_ConfigPin(uint32_t IoPin, IO_ModeTypedef IoMode) +{ + /* Configure the selected IO pin(s) mode */ + IoDrv->Config(IO_I2C_ADDRESS, IoPin, IoMode); + + return IO_OK; +} + +/** + * @brief Sets the IRQ_OUT pin polarity and type + * @param IoIrqOutPinPolarity: High/Low + * @param IoIrqOutPinType: OpenDrain/PushPull + * @retval OK + */ +uint8_t BSP_IO_ConfigIrqOutPin(uint8_t IoIrqOutPinPolarity, uint8_t IoIrqOutPinType) +{ + if((mfxstm32l152Identifier == MFXSTM32L152_ID_1) || (mfxstm32l152Identifier == MFXSTM32L152_ID_2)) + { + /* Initialize the IO driver structure */ + mfxstm32l152_SetIrqOutPinPolarity(IO_I2C_ADDRESS, IoIrqOutPinPolarity); + mfxstm32l152_SetIrqOutPinType(IO_I2C_ADDRESS, IoIrqOutPinType); + } + + return IO_OK; +} + +/** + * @brief Sets the selected pins state. + * @param IoPin: Selected pins to write. + * This parameter can be any combination of the IO pins. + * @param PinState: New pins state to write + * @retval None + */ +void BSP_IO_WritePin(uint32_t IoPin, BSP_IO_PinStateTypeDef PinState) +{ + /* Set the Pin state */ + IoDrv->WritePin(IO_I2C_ADDRESS, IoPin, PinState); +} + +/** + * @brief Gets the selected pins current state. + * @param IoPin: Selected pins to read. + * This parameter can be any combination of the IO pins. + * @retval The current pins state + */ +uint32_t BSP_IO_ReadPin(uint32_t IoPin) +{ + return(IoDrv->ReadPin(IO_I2C_ADDRESS, IoPin)); +} + +/** + * @brief Toggles the selected pins state. + * @param IoPin: Selected pins to toggle. + * This parameter can be any combination of the IO pins. + * @note This function is only used to toggle one pin in the same time + * @retval None + */ +void BSP_IO_TogglePin(uint32_t IoPin) +{ + /* Toggle the current pin state */ + if(IoDrv->ReadPin(IO_I2C_ADDRESS, IoPin) != 0) /* Set */ + { + IoDrv->WritePin(IO_I2C_ADDRESS, IoPin, 0); /* Reset */ + } + else + { + IoDrv->WritePin(IO_I2C_ADDRESS, IoPin, 1); /* Set */ + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_io.h b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_io.h new file mode 100644 index 00000000..1c22f54b --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_io.h @@ -0,0 +1,156 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_io.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32756g_eval_io.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32756G_EVAL_IO_H +#define __STM32756G_EVAL_IO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval.h" +/* Include IO component driver */ +#include "../Components/mfxstm32l152/mfxstm32l152.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @addtogroup STM32756G_EVAL_IO + * @{ + */ + +/** @defgroup STM32756G_EVAL_IO_Exported_Types IO Exported Types + * @{ + */ + +typedef enum +{ + BSP_IO_PIN_RESET = 0, + BSP_IO_PIN_SET = 1 +}BSP_IO_PinStateTypeDef; + +typedef enum +{ + IO_OK = 0, + IO_ERROR = 1, + IO_TIMEOUT = 2 +}IO_StatusTypeDef; +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_IO_Exported_Constants IO Exported Constants + * @{ + */ +#define IO_PIN_0 ((uint32_t)0x0001) +#define IO_PIN_1 ((uint32_t)0x0002) +#define IO_PIN_2 ((uint32_t)0x0004) +#define IO_PIN_3 ((uint32_t)0x0008) +#define IO_PIN_4 ((uint32_t)0x0010) +#define IO_PIN_5 ((uint32_t)0x0020) +#define IO_PIN_6 ((uint32_t)0x0040) +#define IO_PIN_7 ((uint32_t)0x0080) +#define IO_PIN_8 ((uint32_t)0x0100) +#define IO_PIN_9 ((uint32_t)0x0200) +#define IO_PIN_10 ((uint32_t)0x0400) +#define IO_PIN_11 ((uint32_t)0x0800) +#define IO_PIN_12 ((uint32_t)0x1000) +#define IO_PIN_13 ((uint32_t)0x2000) +#define IO_PIN_14 ((uint32_t)0x4000) +#define IO_PIN_15 ((uint32_t)0x8000) +#define IO_PIN_16 ((uint32_t)0x010000) +#define IO_PIN_17 ((uint32_t)0x020000) +#define IO_PIN_18 ((uint32_t)0x040000) +#define IO_PIN_19 ((uint32_t)0x080000) +#define IO_PIN_20 ((uint32_t)0x100000) +#define IO_PIN_21 ((uint32_t)0x200000) +#define IO_PIN_22 ((uint32_t)0x400000) +#define IO_PIN_23 ((uint32_t)0x800000) +#define IO_PIN_ALL ((uint32_t)0xFFFFFF) +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_IO_Exported_Macro IO Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_IO_Exported_Functions IO Exported Functions + * @{ + */ +uint8_t BSP_IO_Init(void); +uint8_t BSP_IO_DeInit(void); +uint8_t BSP_IO_ConfigIrqOutPin(uint8_t IoIrqOutPinPolarity, uint8_t IoIrqOutPinType); +uint32_t BSP_IO_ITGetStatus(uint32_t IoPin); +void BSP_IO_ITClear(void); +uint8_t BSP_IO_ConfigPin(uint32_t IoPin, IO_ModeTypedef IoMode); +void BSP_IO_WritePin(uint32_t IoPin, BSP_IO_PinStateTypeDef PinState); +uint32_t BSP_IO_ReadPin(uint32_t IoPin); +void BSP_IO_TogglePin(uint32_t IoPin); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32756G_EVAL_IO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_lcd.c b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_lcd.c new file mode 100644 index 00000000..52d3b0c4 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_lcd.c @@ -0,0 +1,1626 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_lcd.c + * @author MCD Application Team + * @brief This file includes the driver for Liquid Crystal Display (LCD) module + * mounted on STM32756G-EVAL and STM32746G-EVAL evaluation boards. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive directly an LCD TFT using the LTDC controller. + - This driver selects dynamically the mounted LCD, AMPIRE 640x480 LCD mounted + on MB1063 or AMPIRE 480x272 LCD mounted on MB1046 daughter board, + and uses the adequate timing and setting for the specified LCD using + device ID of the STMPE811 mounted on MB1046 daughter board. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the LCD using the BSP_LCD_Init() function. + o Apply the Layer configuration using the BSP_LCD_LayerDefaultInit() function. + o Select the LCD layer to be used using the BSP_LCD_SelectLayer() function. + o Enable the LCD display using the BSP_LCD_DisplayOn() function. + + + Options + o Configure and enable the colour keying functionality using the + BSP_LCD_SetColorKeying() function. + o Modify in the fly the transparency and/or the frame buffer address + using the following functions: + - BSP_LCD_SetTransparency() + - BSP_LCD_SetLayerAddress() + + + Display on LCD + o Clear the whole LCD using BSP_LCD_Clear() function or only one specified string + line using the BSP_LCD_ClearStringLine() function. + o Display a character on the specified line and column using the BSP_LCD_DisplayChar() + function or a complete string line using the BSP_LCD_DisplayStringAtLine() function. + o Display a string line on the specified position (x,y in pixel) and align mode + using the BSP_LCD_DisplayStringAtLine() function. + o Draw and fill a basic shapes (dot, line, rectangle, circle, ellipse, .. bitmap) + on LCD using the available set of functions. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32756g_eval.c +- stm32756g_eval_sdram.c +- stm32f7xx_hal_dsi.c +- stm32f7xx_hal_ltdc.c +- stm32f7xx_hal_ltdc_ex.c +- stm32f7xx_hal_dma2d.c +- stm32f7xx_hal_rcc_ex.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stmpe811.c +- ampire640480.h +- ampire480272.h +- fonts.h +- font24.c +- font20.c +- font16.c +- font12.c +- font8.c" +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval_lcd.h" +#include "../../../Utilities/Fonts/fonts.h" +#include "../../../Utilities/Fonts/font24.c" +#include "../../../Utilities/Fonts/font20.c" +#include "../../../Utilities/Fonts/font16.c" +#include "../../../Utilities/Fonts/font12.c" +#include "../../../Utilities/Fonts/font8.c" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @defgroup STM32756G_EVAL_LCD STM32756G_EVAL LCD + * @{ + */ + +/** @defgroup STM32756G_EVAL_LCD_Private_TypesDefinitions LCD Private TypesDefinitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LCD_Private_Defines LCD Private Defines + * @{ + */ +#define POLY_X(Z) ((int32_t)((Points + Z)->X)) +#define POLY_Y(Z) ((int32_t)((Points + Z)->Y)) +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LCD_Private_Macros LCD Private Macros + * @{ + */ +#define ABS(X) ((X) > 0 ? (X) : -(X)) +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LCD_Private_Variables LCD Private Variables + * @{ + */ +LTDC_HandleTypeDef hLtdcEval; +static DMA2D_HandleTypeDef hDma2dEval; +static uint32_t PCLK_profile = LCD_MAX_PCLK; +/* Default LCD configuration with LCD Layer 1 */ +static uint32_t ActiveLayer = 0; +static LCD_DrawPropTypeDef DrawProp[MAX_LAYER_NUMBER]; +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LCD_Private_FunctionPrototypes LCD Private FunctionPrototypes + * @{ + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c); +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3); +static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex); +static void LL_ConvertLineToARGB8888(void * pSrc, void *pDst, uint32_t xSize, uint32_t ColorMode); +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LCD_Private_Functions LCD Private Functions + * @{ + */ + +/** + * @brief Initializes the LCD. + * @retval LCD state + */ +uint8_t BSP_LCD_Init(void) +{ + return (BSP_LCD_InitEx(LCD_MAX_PCLK)); +} + +/** + * @brief Initializes the LCD. + * @param PclkConfig : pixel clock profile + * @retval LCD state + */ +uint8_t BSP_LCD_InitEx(uint32_t PclkConfig) +{ + PCLK_profile = PclkConfig; + /* Select the used LCD */ + /* The AMPIRE 480x272 does not contain an ID register then we check the availability + of AMPIRE 480x640 LCD using device ID of the STMPE811 mounted on MB1046 daughter board */ + if(stmpe811_ts_drv.ReadID(TS_I2C_ADDRESS) == STMPE811_ID) + { + /* The AMPIRE LCD 480x272 is selected */ + /* Timing Configuration */ + hLtdcEval.Init.HorizontalSync = (AMPIRE480272_HSYNC - 1); + hLtdcEval.Init.VerticalSync = (AMPIRE480272_VSYNC - 1); + hLtdcEval.Init.AccumulatedHBP = (AMPIRE480272_HSYNC + AMPIRE480272_HBP - 1); + hLtdcEval.Init.AccumulatedVBP = (AMPIRE480272_VSYNC + AMPIRE480272_VBP - 1); + hLtdcEval.Init.AccumulatedActiveH = (AMPIRE480272_HEIGHT + AMPIRE480272_VSYNC + AMPIRE480272_VBP - 1); + hLtdcEval.Init.AccumulatedActiveW = (AMPIRE480272_WIDTH + AMPIRE480272_HSYNC + AMPIRE480272_HBP - 1); + hLtdcEval.Init.TotalHeigh = (AMPIRE480272_HEIGHT + AMPIRE480272_VSYNC + AMPIRE480272_VBP + AMPIRE480272_VFP - 1); + hLtdcEval.Init.TotalWidth = (AMPIRE480272_WIDTH + AMPIRE480272_HSYNC + AMPIRE480272_HBP + AMPIRE480272_HFP - 1); + + /* Initialize the LCD pixel width and pixel height */ + hLtdcEval.LayerCfg->ImageWidth = AMPIRE480272_WIDTH; + hLtdcEval.LayerCfg->ImageHeight = AMPIRE480272_HEIGHT; + } + else + { + /* The LCD AMPIRE 640x480 is selected */ + /* Timing configuration */ + hLtdcEval.Init.HorizontalSync = (AMPIRE640480_HSYNC - 1); + hLtdcEval.Init.VerticalSync = (AMPIRE640480_VSYNC - 1); + hLtdcEval.Init.AccumulatedHBP = (AMPIRE640480_HSYNC + AMPIRE640480_HBP - 1); + hLtdcEval.Init.AccumulatedVBP = (AMPIRE640480_VSYNC + AMPIRE640480_VBP - 1); + hLtdcEval.Init.AccumulatedActiveH = (AMPIRE640480_HEIGHT + AMPIRE640480_VSYNC + AMPIRE640480_VBP - 1); + hLtdcEval.Init.AccumulatedActiveW = (AMPIRE640480_WIDTH + AMPIRE640480_HSYNC + AMPIRE640480_HBP - 1); + hLtdcEval.Init.TotalHeigh = (AMPIRE640480_HEIGHT + AMPIRE640480_VSYNC + AMPIRE640480_VBP + AMPIRE640480_VFP - 1); + hLtdcEval.Init.TotalWidth = (AMPIRE640480_WIDTH + AMPIRE640480_HSYNC + AMPIRE640480_HBP + AMPIRE640480_HFP - 1); + + /* Initialize the LCD pixel width and pixel height */ + hLtdcEval.LayerCfg->ImageWidth = AMPIRE640480_WIDTH; + hLtdcEval.LayerCfg->ImageHeight = AMPIRE640480_HEIGHT; + } + + /* Background value */ + hLtdcEval.Init.Backcolor.Blue = 0; + hLtdcEval.Init.Backcolor.Green = 0; + hLtdcEval.Init.Backcolor.Red = 0; + + /* Polarity */ + hLtdcEval.Init.HSPolarity = LTDC_HSPOLARITY_AL; + hLtdcEval.Init.VSPolarity = LTDC_VSPOLARITY_AL; + hLtdcEval.Init.DEPolarity = LTDC_DEPOLARITY_AL; + hLtdcEval.Init.PCPolarity = LTDC_PCPOLARITY_IPC; + hLtdcEval.Instance = LTDC; + + /* LCD clock configuration */ + BSP_LCD_ClockConfig(&hLtdcEval, &PCLK_profile); + + if(HAL_LTDC_GetState(&hLtdcEval) == HAL_LTDC_STATE_RESET) + { + /* Initialize the LCD Msp: this __weak function can be rewritten by the application */ + BSP_LCD_MspInit(&hLtdcEval, NULL); + } + HAL_LTDC_Init(&hLtdcEval); + +#if !defined(DATA_IN_ExtSDRAM) + /* When DATA_IN_ExtSDRAM define is enabled, the SDRAM will be configured in SystemInit() + function (from system_stm32f7xx.c) before branch to main() routine. In such case, there + is no need to reconfigure the SDRAM within the LCD driver, since it's already initialized. + Otherwise the SDRAM must be configured. */ + BSP_SDRAM_Init(); +#endif + + /* Initialize the font */ + BSP_LCD_SetFont(&LCD_DEFAULT_FONT); + + return LCD_OK; +} + +/** + * @brief DeInitializes the LCD. + * @retval LCD state + */ +uint8_t BSP_LCD_DeInit(void) +{ + /* Initialize the hltdc_eval Instance parameter */ + hLtdcEval.Instance = LTDC; + + /* Disable LTDC block */ + __HAL_LTDC_DISABLE(&hLtdcEval); + + /* DeInit the LTDC */ + HAL_LTDC_DeInit(&hLtdcEval); + + /* DeInit the LTDC MSP : this __weak function can be rewritten by the application */ + BSP_LCD_MspDeInit(&hLtdcEval, NULL); + + return LCD_OK; +} + +/** + * @brief Gets the LCD X size. + * @retval Used LCD X size + */ +uint32_t BSP_LCD_GetXSize(void) +{ + return hLtdcEval.LayerCfg[ActiveLayer].ImageWidth; +} + +/** + * @brief Gets the LCD Y size. + * @retval Used LCD Y size + */ +uint32_t BSP_LCD_GetYSize(void) +{ + return hLtdcEval.LayerCfg[ActiveLayer].ImageHeight; +} + +/** + * @brief Set the LCD X size. + * @param imageWidthPixels : image width in pixels unit + * @retval None + */ +void BSP_LCD_SetXSize(uint32_t imageWidthPixels) +{ + hLtdcEval.LayerCfg[ActiveLayer].ImageWidth = imageWidthPixels; +} + +/** + * @brief Set the LCD Y size. + * @param imageHeightPixels : image height in lines unit + * @retval None + */ +void BSP_LCD_SetYSize(uint32_t imageHeightPixels) +{ + hLtdcEval.LayerCfg[ActiveLayer].ImageHeight = imageHeightPixels; +} + +/** + * @brief Initializes the LCD layers. + * @param LayerIndex: Layer foreground or background + * @param FB_Address: Layer frame buffer + * @retval None + */ +void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) +{ + LCD_LayerCfgTypeDef layer_cfg; + + /* Layer Init */ + layer_cfg.WindowX0 = 0; + layer_cfg.WindowX1 = BSP_LCD_GetXSize(); + layer_cfg.WindowY0 = 0; + layer_cfg.WindowY1 = BSP_LCD_GetYSize(); + layer_cfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888; + layer_cfg.FBStartAdress = FB_Address; + layer_cfg.Alpha = 255; + layer_cfg.Alpha0 = 0; + layer_cfg.Backcolor.Blue = 0; + layer_cfg.Backcolor.Green = 0; + layer_cfg.Backcolor.Red = 0; + layer_cfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; + layer_cfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; + layer_cfg.ImageWidth = BSP_LCD_GetXSize(); + layer_cfg.ImageHeight = BSP_LCD_GetYSize(); + + HAL_LTDC_ConfigLayer(&hLtdcEval, &layer_cfg, LayerIndex); + + DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE; + DrawProp[LayerIndex].pFont = &Font24; + DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK; +} + +/** + * @brief Selects the LCD Layer. + * @param LayerIndex: Layer foreground or background + * @retval None + */ +void BSP_LCD_SelectLayer(uint32_t LayerIndex) +{ + ActiveLayer = LayerIndex; +} + +/** + * @brief Sets an LCD Layer visible + * @param LayerIndex: Visible Layer + * @param State: New state of the specified layer + * This parameter can be one of the following values: + * @arg ENABLE + * @arg DISABLE + * @retval None + */ +void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState State) +{ + if(State == ENABLE) + { + __HAL_LTDC_LAYER_ENABLE(&hLtdcEval, LayerIndex); + } + else + { + __HAL_LTDC_LAYER_DISABLE(&hLtdcEval, LayerIndex); + } + __HAL_LTDC_RELOAD_CONFIG(&hLtdcEval); +} + +/** + * @brief Sets an LCD Layer visible without reloading. + * @param LayerIndex: Visible Layer + * @param State: New state of the specified layer + * This parameter can be one of the following values: + * @arg ENABLE + * @arg DISABLE + * @retval None + */ +void BSP_LCD_SetLayerVisible_NoReload(uint32_t LayerIndex, FunctionalState State) +{ + if(State == ENABLE) + { + __HAL_LTDC_LAYER_ENABLE(&hLtdcEval, LayerIndex); + } + else + { + __HAL_LTDC_LAYER_DISABLE(&hLtdcEval, LayerIndex); + } + /* Do not Sets the Reload */ +} + +/** + * @brief Configures the transparency. + * @param LayerIndex: Layer foreground or background. + * @param Transparency: Transparency + * This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF + * @retval None + */ +void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency) +{ + HAL_LTDC_SetAlpha(&hLtdcEval, Transparency, LayerIndex); +} + +/** + * @brief Configures the transparency without reloading. + * @param LayerIndex: Layer foreground or background. + * @param Transparency: Transparency + * This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF + * @retval None + */ +void BSP_LCD_SetTransparency_NoReload(uint32_t LayerIndex, uint8_t Transparency) +{ + HAL_LTDC_SetAlpha_NoReload(&hLtdcEval, Transparency, LayerIndex); +} + +/** + * @brief Sets an LCD layer frame buffer address. + * @param LayerIndex: Layer foreground or background + * @param Address: New LCD frame buffer value + * @retval None + */ +void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address) +{ + HAL_LTDC_SetAddress(&hLtdcEval, Address, LayerIndex); +} + +/** + * @brief Sets an LCD layer frame buffer address without reloading. + * @param LayerIndex: Layer foreground or background + * @param Address: New LCD frame buffer value + * @retval None + */ +void BSP_LCD_SetLayerAddress_NoReload(uint32_t LayerIndex, uint32_t Address) +{ + HAL_LTDC_SetAddress_NoReload(&hLtdcEval, Address, LayerIndex); +} + +/** + * @brief Sets display window. + * @param LayerIndex: Layer index + * @param Xpos: LCD X position + * @param Ypos: LCD Y position + * @param Width: LCD window width + * @param Height: LCD window height + * @retval None + */ +void BSP_LCD_SetLayerWindow(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Reconfigure the layer size */ + HAL_LTDC_SetWindowSize(&hLtdcEval, Width, Height, LayerIndex); + + /* Reconfigure the layer position */ + HAL_LTDC_SetWindowPosition(&hLtdcEval, Xpos, Ypos, LayerIndex); +} + +/** + * @brief Sets display window without reloading. + * @param LayerIndex: Layer index + * @param Xpos: LCD X position + * @param Ypos: LCD Y position + * @param Width: LCD window width + * @param Height: LCD window height + * @retval None + */ +void BSP_LCD_SetLayerWindow_NoReload(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Reconfigure the layer size */ + HAL_LTDC_SetWindowSize_NoReload(&hLtdcEval, Width, Height, LayerIndex); + + /* Reconfigure the layer position */ + HAL_LTDC_SetWindowPosition_NoReload(&hLtdcEval, Xpos, Ypos, LayerIndex); +} + +/** + * @brief Configures and sets the color keying. + * @param LayerIndex: Layer foreground or background + * @param RGBValue: Color reference + * @retval None + */ +void BSP_LCD_SetColorKeying(uint32_t LayerIndex, uint32_t RGBValue) +{ + /* Configure and Enable the color Keying for LCD Layer */ + HAL_LTDC_ConfigColorKeying(&hLtdcEval, RGBValue, LayerIndex); + HAL_LTDC_EnableColorKeying(&hLtdcEval, LayerIndex); +} + +/** + * @brief Configures and sets the color keying without reloading. + * @param LayerIndex: Layer foreground or background + * @param RGBValue: Color reference + * @retval None + */ +void BSP_LCD_SetColorKeying_NoReload(uint32_t LayerIndex, uint32_t RGBValue) +{ + /* Configure and Enable the color Keying for LCD Layer */ + HAL_LTDC_ConfigColorKeying_NoReload(&hLtdcEval, RGBValue, LayerIndex); + HAL_LTDC_EnableColorKeying_NoReload(&hLtdcEval, LayerIndex); +} + +/** + * @brief Disables the color keying. + * @param LayerIndex: Layer foreground or background + * @retval None + */ +void BSP_LCD_ResetColorKeying(uint32_t LayerIndex) +{ + /* Disable the color Keying for LCD Layer */ + HAL_LTDC_DisableColorKeying(&hLtdcEval, LayerIndex); +} + +/** + * @brief Disables the color keying without reloading. + * @param LayerIndex: Layer foreground or background + * @retval None + */ +void BSP_LCD_ResetColorKeying_NoReload(uint32_t LayerIndex) +{ + /* Disable the color Keying for LCD Layer */ + HAL_LTDC_DisableColorKeying_NoReload(&hLtdcEval, LayerIndex); +} + +/** + * @brief Disables the color keying without reloading. + * @param ReloadType: can be one of the following values + * - LCD_RELOAD_IMMEDIATE + * - LCD_RELOAD_VERTICAL_BLANKING + * @retval None + */ +void BSP_LCD_Relaod(uint32_t ReloadType) +{ + HAL_LTDC_Reload (&hLtdcEval, ReloadType); +} + +/** + * @brief Sets the LCD text color. + * @param Color: Text color code ARGB(8-8-8-8) + * @retval None + */ +void BSP_LCD_SetTextColor(uint32_t Color) +{ + DrawProp[ActiveLayer].TextColor = Color; +} + +/** + * @brief Gets the LCD text color. + * @retval Used text color. + */ +uint32_t BSP_LCD_GetTextColor(void) +{ + return DrawProp[ActiveLayer].TextColor; +} + +/** + * @brief Sets the LCD background color. + * @param Color: Layer background color code ARGB(8-8-8-8) + * @retval None + */ +void BSP_LCD_SetBackColor(uint32_t Color) +{ + DrawProp[ActiveLayer].BackColor = Color; +} + +/** + * @brief Gets the LCD background color. + * @retval Used background color + */ +uint32_t BSP_LCD_GetBackColor(void) +{ + return DrawProp[ActiveLayer].BackColor; +} + +/** + * @brief Sets the LCD text font. + * @param fonts: Layer font to be used + * @retval None + */ +void BSP_LCD_SetFont(sFONT *fonts) +{ + DrawProp[ActiveLayer].pFont = fonts; +} + +/** + * @brief Gets the LCD text font. + * @retval Used layer font + */ +sFONT *BSP_LCD_GetFont(void) +{ + return DrawProp[ActiveLayer].pFont; +} + +/** + * @brief Reads an LCD pixel. + * @param Xpos: X position + * @param Ypos: Y position + * @retval RGB pixel color + */ +uint32_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos) +{ + uint32_t ret = 0; + + if(hLtdcEval.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint32_t*) (hLtdcEval.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + else if(hLtdcEval.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB888) + { + /* Read data value from SDRAM memory */ + ret = (*(__IO uint32_t*) (hLtdcEval.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))) & 0x00FFFFFF); + } + else if((hLtdcEval.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \ + (hLtdcEval.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \ + (hLtdcEval.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_AL88)) + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint16_t*) (hLtdcEval.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + else + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint8_t*) (hLtdcEval.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + + return ret; +} + +/** + * @brief Clears the hole LCD. + * @param Color: Color of the background + * @retval None + */ +void BSP_LCD_Clear(uint32_t Color) +{ + /* Clear the LCD */ + LL_FillBuffer(ActiveLayer, (uint32_t *)(hLtdcEval.LayerCfg[ActiveLayer].FBStartAdress), BSP_LCD_GetXSize(), BSP_LCD_GetYSize(), 0, Color); +} + +/** + * @brief Clears the selected line. + * @param Line: Line to be cleared + * @retval None + */ +void BSP_LCD_ClearStringLine(uint32_t Line) +{ + uint32_t color_backup = DrawProp[ActiveLayer].TextColor; + DrawProp[ActiveLayer].TextColor = DrawProp[ActiveLayer].BackColor; + + /* Draw rectangle with background color */ + BSP_LCD_FillRect(0, (Line * DrawProp[ActiveLayer].pFont->Height), BSP_LCD_GetXSize(), DrawProp[ActiveLayer].pFont->Height); + + DrawProp[ActiveLayer].TextColor = color_backup; + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Displays one character. + * @param Xpos: Start column address + * @param Ypos: Line where to display the character shape. + * @param Ascii: Character ascii code + * This parameter must be a number between Min_Data = 0x20 and Max_Data = 0x7E + * @retval None + */ +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii) +{ + DrawChar(Xpos, Ypos, &DrawProp[ActiveLayer].pFont->table[(Ascii-' ') *\ + DrawProp[ActiveLayer].pFont->Height * ((DrawProp[ActiveLayer].pFont->Width + 7) / 8)]); +} + +/** + * @brief Displays characters on the LCD. + * @param Xpos: X position (in pixel) + * @param Ypos: Y position (in pixel) + * @param Text: Pointer to string to display on LCD + * @param Mode: Display mode + * This parameter can be one of the following values: + * @arg CENTER_MODE + * @arg RIGHT_MODE + * @arg LEFT_MODE + * @retval None + */ +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode) +{ + uint16_t ref_column = 1, i = 0; + uint32_t size = 0, xsize = 0; + uint8_t *ptr = Text; + + /* Get the text size */ + while (*ptr++) size ++ ; + + /* Characters number per line */ + xsize = (BSP_LCD_GetXSize()/DrawProp[ActiveLayer].pFont->Width); + + switch (Mode) + { + case CENTER_MODE: + { + ref_column = Xpos + ((xsize - size)* DrawProp[ActiveLayer].pFont->Width) / 2; + break; + } + case LEFT_MODE: + { + ref_column = Xpos; + break; + } + case RIGHT_MODE: + { + ref_column = - Xpos + ((xsize - size)*DrawProp[ActiveLayer].pFont->Width); + break; + } + default: + { + ref_column = Xpos; + break; + } + } + + /* Check that the Start column is located in the screen */ + if ((ref_column < 1) || (ref_column >= 0x8000)) + { + ref_column = 1; + } + + /* Send the string character by character on LCD */ + while ((*Text != 0) & (((BSP_LCD_GetXSize() - (i*DrawProp[ActiveLayer].pFont->Width)) & 0xFFFF) >= DrawProp[ActiveLayer].pFont->Width)) + { + /* Display one character on LCD */ + BSP_LCD_DisplayChar(ref_column, Ypos, *Text); + /* Decrement the column position by 16 */ + ref_column += DrawProp[ActiveLayer].pFont->Width; + /* Point on the next character */ + Text++; + i++; + } +} + +/** + * @brief Displays a maximum of 60 characters on the LCD. + * @param Line: Line where to display the character shape + * @param ptr: Pointer to string to display on LCD + * @retval None + */ +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr) +{ + BSP_LCD_DisplayStringAt(0, LINE(Line), ptr, LEFT_MODE); +} + +/** + * @brief Draws an horizontal line. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + * @retval None + */ +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t Xaddress = 0; + + /* Get the line address */ + Xaddress = (hLtdcEval.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + + /* Write line */ + LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, Length, 1, 0, DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws a vertical line. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + * @retval None + */ +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t Xaddress = 0; + + /* Get the line address */ + Xaddress = (hLtdcEval.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + + /* Write line */ + LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, 1, Length, (BSP_LCD_GetXSize() - 1), DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws an uni-line (between two points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @retval None + */ +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, num_add = 0, num_pixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + num_add = deltay; + num_pixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + num_add = deltax; + num_pixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= num_pixels; curpixel++) + { + BSP_LCD_DrawPixel(x, y, DrawProp[ActiveLayer].TextColor); /* Draw the current pixel */ + num += num_add; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Draws a rectangle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + * @retval None + */ +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Draw horizontal lines */ + BSP_LCD_DrawHLine(Xpos, Ypos, Width); + BSP_LCD_DrawHLine(Xpos, (Ypos+ Height), Width); + + /* Draw vertical lines */ + BSP_LCD_DrawVLine(Xpos, Ypos, Height); + BSP_LCD_DrawVLine((Xpos + Width), Ypos, Height); +} + +/** + * @brief Draws a circle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + * @retval None + */ +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t decision; /* Decision Variable */ + uint32_t current_x; /* Current X Value */ + uint32_t current_y; /* Current Y Value */ + + decision = 3 - (Radius << 1); + current_x = 0; + current_y = Radius; + + while (current_x <= current_y) + { + BSP_LCD_DrawPixel((Xpos + current_x), (Ypos - current_y), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - current_x), (Ypos - current_y), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + current_y), (Ypos - current_x), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - current_y), (Ypos - current_x), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + current_x), (Ypos + current_y), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - current_x), (Ypos + current_y), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + current_y), (Ypos + current_x), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - current_y), (Ypos + current_x), DrawProp[ActiveLayer].TextColor); + + if (decision < 0) + { + decision += (current_x << 2) + 6; + } + else + { + decision += ((current_x - current_y) << 2) + 10; + current_y--; + } + current_x++; + } +} + +/** + * @brief Draws an poly-line (between many points). + * @param Points: Pointer to the points array + * @param PointCount: Number of points + * @retval None + */ +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t x = 0, y = 0; + + if(PointCount < 2) + { + return; + } + + BSP_LCD_DrawLine(Points->X, Points->Y, (Points+PointCount-1)->X, (Points+PointCount-1)->Y); + + while(--PointCount) + { + x = Points->X; + y = Points->Y; + Points++; + BSP_LCD_DrawLine(x, y, Points->X, Points->Y); + } +} + +/** + * @brief Draws an ellipse on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + * @retval None + */ +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float k = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + k = (float)(rad2/rad1); + + do { + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/k)), (Ypos+y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/k)), (Ypos+y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/k)), (Ypos-y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/k)), (Ypos-y), DrawProp[ActiveLayer].TextColor); + + e2 = err; + if (e2 <= x) { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Draws a pixel on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param RGB_Code: Pixel color in ARGB mode (8-8-8-8) + * @retval None + */ +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t RGB_Code) +{ + /* Write data value to all SDRAM memory */ + *(__IO uint32_t*) (hLtdcEval.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))) = RGB_Code; +} + +/** + * @brief Draws a bitmap picture loaded in the internal Flash (32 bpp). + * @param Xpos: Bmp X position in the LCD + * @param Ypos: Bmp Y position in the LCD + * @param pbmp: Pointer to Bmp picture address in the internal Flash + * @retval None + */ +void BSP_LCD_DrawBitmap(uint32_t Xpos, uint32_t Ypos, uint8_t *pbmp) +{ + uint32_t index = 0, width = 0, height = 0, bit_pixel = 0; + uint32_t address; + uint32_t input_color_mode = 0; + + /* Get bitmap data address offset */ + index = pbmp[10] + (pbmp[11] << 8) + (pbmp[12] << 16) + (pbmp[13] << 24); + + /* Read bitmap width */ + width = pbmp[18] + (pbmp[19] << 8) + (pbmp[20] << 16) + (pbmp[21] << 24); + + /* Read bitmap height */ + height = pbmp[22] + (pbmp[23] << 8) + (pbmp[24] << 16) + (pbmp[25] << 24); + + /* Read bit/pixel */ + bit_pixel = pbmp[28] + (pbmp[29] << 8); + + /* Set the address */ + address = hLtdcEval.LayerCfg[ActiveLayer].FBStartAdress + (((BSP_LCD_GetXSize()*Ypos) + Xpos)*(4)); + + /* Get the layer pixel format */ + if ((bit_pixel/8) == 4) + { + input_color_mode = DMA2D_INPUT_ARGB8888; + } + else if ((bit_pixel/8) == 2) + { + input_color_mode = DMA2D_INPUT_RGB565; + } + else + { + input_color_mode = DMA2D_INPUT_RGB888; + } + + /* Bypass the bitmap header */ + pbmp += (index + (width * (height - 1) * (bit_pixel/8))); + + /* Convert picture to ARGB8888 pixel format */ + for(index=0; index < height; index++) + { + /* Pixel format conversion */ + LL_ConvertLineToARGB8888((uint32_t *)pbmp, (uint32_t *)address, width, input_color_mode); + + /* Increment the source and destination buffers */ + address+= (BSP_LCD_GetXSize()*4); + pbmp -= width*(bit_pixel/8); + } +} + +/** + * @brief Draws a full rectangle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + * @retval None + */ +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + uint32_t x_address = 0; + + /* Set the text color */ + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + + /* Get the rectangle start address */ + x_address = (hLtdcEval.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + + /* Fill the rectangle */ + LL_FillBuffer(ActiveLayer, (uint32_t *)x_address, Width, Height, (BSP_LCD_GetXSize() - Width), DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws a full circle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + * @retval None + */ +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t decision; /* Decision Variable */ + uint32_t current_x; /* Current X Value */ + uint32_t current_y; /* Current Y Value */ + + decision = 3 - (Radius << 1); + + current_x = 0; + current_y = Radius; + + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + + while (current_x <= current_y) + { + if(current_y > 0) + { + BSP_LCD_DrawHLine(Xpos - current_y, Ypos + current_x, 2*current_y); + BSP_LCD_DrawHLine(Xpos - current_y, Ypos - current_x, 2*current_y); + } + + if(current_x > 0) + { + BSP_LCD_DrawHLine(Xpos - current_x, Ypos - current_y, 2*current_x); + BSP_LCD_DrawHLine(Xpos - current_x, Ypos + current_y, 2*current_x); + } + if (decision < 0) + { + decision += (current_x << 2) + 6; + } + else + { + decision += ((current_x - current_y) << 2) + 10; + current_y--; + } + current_x++; + } + + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawCircle(Xpos, Ypos, Radius); +} + +/** + * @brief Draws a full poly-line (between many points). + * @param Points: Pointer to the points array + * @param PointCount: Number of points + * @retval None + */ +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t X = 0, Y = 0, X2 = 0, Y2 = 0, X_center = 0, Y_center = 0, X_first = 0, Y_first = 0, pixelX = 0, pixelY = 0, counter = 0; + uint16_t image_left = 0, image_right = 0, image_top = 0, image_bottom = 0; + + image_left = image_right = Points->X; + image_top= image_bottom = Points->Y; + + for(counter = 1; counter < PointCount; counter++) + { + pixelX = POLY_X(counter); + if(pixelX < image_left) + { + image_left = pixelX; + } + if(pixelX > image_right) + { + image_right = pixelX; + } + + pixelY = POLY_Y(counter); + if(pixelY < image_top) + { + image_top = pixelY; + } + if(pixelY > image_bottom) + { + image_bottom = pixelY; + } + } + + if(PointCount < 2) + { + return; + } + + X_center = (image_left + image_right)/2; + Y_center = (image_bottom + image_top)/2; + + X_first = Points->X; + Y_first = Points->Y; + + while(--PointCount) + { + X = Points->X; + Y = Points->Y; + Points++; + X2 = Points->X; + Y2 = Points->Y; + + FillTriangle(X, X2, X_center, Y, Y2, Y_center); + FillTriangle(X, X_center, X2, Y, Y_center, Y2); + FillTriangle(X_center, X2, X, Y_center, Y2, Y); + } + + FillTriangle(X_first, X2, X_center, Y_first, Y2, Y_center); + FillTriangle(X_first, X_center, X2, Y_first, Y_center, Y2); + FillTriangle(X_center, X2, X_first, Y_center, Y2, Y_first); +} + +/** + * @brief Draws a full ellipse. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + * @retval None + */ +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float k = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + k = (float)(rad2/rad1); + + do + { + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/k)), (Ypos+y), (2*(uint16_t)(x/k) + 1)); + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/k)), (Ypos-y), (2*(uint16_t)(x/k) + 1)); + + e2 = err; + if (e2 <= x) + { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Enables the display. + * @retval None + */ +void BSP_LCD_DisplayOn(void) +{ + /* Display On */ + __HAL_LTDC_ENABLE(&hLtdcEval); +} + +/** + * @brief Disables the display. + * @retval None + */ +void BSP_LCD_DisplayOff(void) +{ + /* Display Off */ + __HAL_LTDC_DISABLE(&hLtdcEval); +} + +/** + * @brief Initializes the LTDC MSP. + * @param hltdc: LTDC handle + * @param Params + * @retval None + */ +__weak void BSP_LCD_MspInit(LTDC_HandleTypeDef *hltdc, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable the LTDC and DMA2D clocks */ + __HAL_RCC_LTDC_CLK_ENABLE(); + __HAL_RCC_DMA2D_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOI_CLK_ENABLE(); + __HAL_RCC_GPIOJ_CLK_ENABLE(); + __HAL_RCC_GPIOK_CLK_ENABLE(); + + /*** LTDC Pins configuration ***/ + /* GPIOI configuration */ + gpio_init_structure.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = GPIO_AF14_LTDC; + HAL_GPIO_Init(GPIOI, &gpio_init_structure); + + /* GPIOJ configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \ + GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | \ + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | \ + GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = GPIO_AF14_LTDC; + HAL_GPIO_Init(GPIOJ, &gpio_init_structure); + + /* GPIOK configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \ + GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = GPIO_AF14_LTDC; + HAL_GPIO_Init(GPIOK, &gpio_init_structure); +} + +/** + * @brief DeInitializes BSP_LCD MSP. + * @param hltdc: LTDC handle + * @param Params + * @retval None + */ +__weak void BSP_LCD_MspDeInit(LTDC_HandleTypeDef *hltdc, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Disable LTDC block */ + __HAL_LTDC_DISABLE(hltdc); + + /* LTDC Pins deactivation */ + /* GPIOI deactivation */ + gpio_init_structure.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_DeInit(GPIOI, gpio_init_structure.Pin); + /* GPIOJ deactivation */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \ + GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | \ + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | \ + GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_DeInit(GPIOJ, gpio_init_structure.Pin); + /* GPIOK deactivation */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \ + GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; + HAL_GPIO_DeInit(GPIOK, gpio_init_structure.Pin); + + /* Disable LTDC clock */ + __HAL_RCC_LTDC_CLK_DISABLE(); + + /* GPIO pins clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Clock Config. + * @param hltdc: LTDC handle + * @param Params + * @note This API is called by BSP_LCD_Init() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_LCD_ClockConfig(LTDC_HandleTypeDef *hltdc, void *Params) +{ + static RCC_PeriphCLKInitTypeDef periph_clk_init_struct; + + if(stmpe811_ts_drv.ReadID(TS_I2C_ADDRESS) == STMPE811_ID) + { + /* AMPIRE480272 LCD clock configuration */ + /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */ + /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 Mhz */ + /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/5 = 38.4 Mhz */ + /* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_4 = 38.4/4 = 9.6Mhz */ + periph_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; + periph_clk_init_struct.PLLSAI.PLLSAIN = 192; + periph_clk_init_struct.PLLSAI.PLLSAIR = AMPIRE480272_FREQUENCY_DIVIDER; + periph_clk_init_struct.PLLSAIDivR = RCC_PLLSAIDIVR_4; + HAL_RCCEx_PeriphCLKConfig(&periph_clk_init_struct); + } + else + { + /* The programmed LTDC pixel clock depends on the vertical refresh rate of the panel 60Hz => 25.16MHz and + the LCD/SDRAM bandwidth affected by the several access on the bus and the number of used layers. + */ + if(*(uint32_t *)Params == LCD_MAX_PCLK) + { + /* In case of single layer the bandwidth is arround 160MBytesPerSec ==> theorical PCLK of 40MHz */ + /* AMPIRE640480 typical PCLK is 25.16 MHz so the PLLSAI is configured to provide this clock */ + /* AMPIRE640480 LCD clock configuration */ + /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */ + /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 151 Mhz */ + /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 151/3 = 50.3 Mhz */ + /* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_2 = 50.3/2 = 25.16 Mhz */ + periph_clk_init_struct.PLLSAI.PLLSAIN = 151; + } + else + { + /* In case of double layers the bandwidth is arround 80MBytesPerSec => 20MHz (<25,16MHz) */ + /* so the PLLSAI is configured to provide this clock */ + /* AMPIRE640480 LCD clock configuration */ + /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */ + /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 120 Mhz */ + /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 120/3 = 40 Mhz */ + /* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_2 = 40/2 = 20 Mhz */ + periph_clk_init_struct.PLLSAI.PLLSAIN = 120; + } + periph_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; + periph_clk_init_struct.PLLSAI.PLLSAIR = 3; + periph_clk_init_struct.PLLSAIDivR = RCC_PLLSAIDIVR_2; + HAL_RCCEx_PeriphCLKConfig(&periph_clk_init_struct); + } +} + + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Draws a character on LCD. + * @param Xpos: Line where to display the character shape + * @param Ypos: Start column address + * @param c: Pointer to the character data + * @retval None + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c) +{ + uint32_t i = 0, j = 0; + uint16_t height, width; + uint8_t offset; + uint8_t *pchar; + uint32_t line; + + height = DrawProp[ActiveLayer].pFont->Height; + width = DrawProp[ActiveLayer].pFont->Width; + + offset = 8 *((width + 7)/8) - width ; + + for(i = 0; i < height; i++) + { + pchar = ((uint8_t *)c + (width + 7)/8 * i); + + switch(((width + 7)/8)) + { + + case 1: + line = pchar[0]; + break; + + case 2: + line = (pchar[0]<< 8) | pchar[1]; + break; + + case 3: + default: + line = (pchar[0]<< 16) | (pchar[1]<< 8) | pchar[2]; + break; + } + + for (j = 0; j < width; j++) + { + if(line & (1 << (width- j + offset- 1))) + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp[ActiveLayer].TextColor); + } + else + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp[ActiveLayer].BackColor); + } + } + Ypos++; + } +} + +/** + * @brief Fills a triangle (between 3 points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @param x3: Point 3 X position + * @param y3: Point 3 Y position + * @retval None + */ +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, num_add = 0, num_pixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + num_add = deltay; + num_pixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + num_add = deltax; + num_pixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= num_pixels; curpixel++) + { + BSP_LCD_DrawLine(x, y, x3, y3); + + num += num_add; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Fills a buffer. + * @param LayerIndex: Layer index + * @param pDst: Pointer to destination buffer + * @param xSize: Buffer width + * @param ySize: Buffer height + * @param OffLine: Offset + * @param ColorIndex: Color index + * @retval None + */ +static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex) +{ + /* Register to memory mode with ARGB8888 as color Mode */ + hDma2dEval.Init.Mode = DMA2D_R2M; + hDma2dEval.Init.ColorMode = DMA2D_OUTPUT_ARGB8888; + hDma2dEval.Init.OutputOffset = OffLine; + + hDma2dEval.Instance = DMA2D; + + /* DMA2D Initialization */ + if(HAL_DMA2D_Init(&hDma2dEval) == HAL_OK) + { + if(HAL_DMA2D_ConfigLayer(&hDma2dEval, LayerIndex) == HAL_OK) + { + if (HAL_DMA2D_Start(&hDma2dEval, ColorIndex, (uint32_t)pDst, xSize, ySize) == HAL_OK) + { + /* Polling For DMA transfer */ + HAL_DMA2D_PollForTransfer(&hDma2dEval, 10); + } + } + } +} + +/** + * @brief Converts a line to an ARGB8888 pixel format. + * @param pSrc: Pointer to source buffer + * @param pDst: Output color + * @param xSize: Buffer width + * @param ColorMode: Input color mode + * @retval None + */ +static void LL_ConvertLineToARGB8888(void *pSrc, void *pDst, uint32_t xSize, uint32_t ColorMode) +{ + /* Configure the DMA2D Mode, Color Mode and output offset */ + hDma2dEval.Init.Mode = DMA2D_M2M_PFC; + hDma2dEval.Init.ColorMode = DMA2D_OUTPUT_ARGB8888; + hDma2dEval.Init.OutputOffset = 0; + + /* Foreground Configuration */ + hDma2dEval.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; + hDma2dEval.LayerCfg[1].InputAlpha = 0xFF; + hDma2dEval.LayerCfg[1].InputColorMode = ColorMode; + hDma2dEval.LayerCfg[1].InputOffset = 0; + + hDma2dEval.Instance = DMA2D; + + /* DMA2D Initialization */ + if(HAL_DMA2D_Init(&hDma2dEval) == HAL_OK) + { + if(HAL_DMA2D_ConfigLayer(&hDma2dEval, 1) == HAL_OK) + { + if (HAL_DMA2D_Start(&hDma2dEval, (uint32_t)pSrc, (uint32_t)pDst, xSize, 1) == HAL_OK) + { + /* Polling For DMA transfer */ + HAL_DMA2D_PollForTransfer(&hDma2dEval, 10); + } + } + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_lcd.h b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_lcd.h new file mode 100644 index 00000000..0a0be941 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_lcd.h @@ -0,0 +1,270 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_lcd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32756g_eval_lcd.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32756G_EVAL_LCD_H +#define __STM32756G_EVAL_LCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include LCD component Driver */ +/* LCD integrated within MB1063 */ +#include "../Components/ampire640480/ampire640480.h" +/* LCD integrated within MB1046 */ +#include "../Components/ampire480272/ampire480272.h" + +/* Include IOExpander(STMPE811) component Driver */ +#include "../Components/stmpe811/stmpe811.h" + +/* Include SDRAM Driver */ +#include "stm32756g_eval_sdram.h" + +#include "stm32756g_eval.h" +#include "../../../Utilities/Fonts/fonts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @addtogroup STM32756G_EVAL_LCD + * @{ + */ + +/** @defgroup STM32756G_EVAL_LCD_Exported_Types LCD Exported Types + * @{ + */ +typedef struct +{ + uint32_t TextColor; + uint32_t BackColor; + sFONT *pFont; +}LCD_DrawPropTypeDef; + +typedef struct +{ + int16_t X; + int16_t Y; +}Point, * pPoint; + +/** + * @brief Line mode structures definition + */ +typedef enum +{ + CENTER_MODE = 0x01, /* Center mode */ + RIGHT_MODE = 0x02, /* Right mode */ + LEFT_MODE = 0x03 /* Left mode */ +}Text_AlignModeTypdef; + +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LCD_Exported_Constants LCD Exported Constants + * @{ + */ +#define MAX_LAYER_NUMBER ((uint32_t)2) + +#define LCD_LayerCfgTypeDef LTDC_LayerCfgTypeDef + +#define LTDC_ACTIVE_LAYER ((uint32_t)1) /* Layer 1 */ +/** + * @brief LCD status structure definition + */ +#define LCD_OK ((uint8_t)0x00) +#define LCD_ERROR ((uint8_t)0x01) +#define LCD_TIMEOUT ((uint8_t)0x02) + +/** + * @brief LCD FB_StartAddress + */ +#define LCD_FB_START_ADDRESS ((uint32_t)0xC0000000) + + +/** + * @brief LCD Layer_Number + */ + +/* The programmed LTDC pixel clock depends on the vertical refresh rate of the panel 60Hz => 25.16MHz and + the LCD/SDRAM bandwidth affected by the several access on the bus and the number of used layers. + when only one layer is enabled "LCD_MAX_PCLK" can be used and when two layers are enabled simultaneously + or/and there is several access on the bus "LCD_MIN_PCLK" parameter is recommended */ +#define LCD_MAX_PCLK ((uint8_t)0x00) +#define LCD_MIN_PCLK ((uint8_t)0x01) + + +/** + * @brief LCD color + */ +#define LCD_COLOR_BLUE ((uint32_t)0xFF0000FF) +#define LCD_COLOR_GREEN ((uint32_t)0xFF00FF00) +#define LCD_COLOR_RED ((uint32_t)0xFFFF0000) +#define LCD_COLOR_CYAN ((uint32_t)0xFF00FFFF) +#define LCD_COLOR_MAGENTA ((uint32_t)0xFFFF00FF) +#define LCD_COLOR_YELLOW ((uint32_t)0xFFFFFF00) +#define LCD_COLOR_LIGHTBLUE ((uint32_t)0xFF8080FF) +#define LCD_COLOR_LIGHTGREEN ((uint32_t)0xFF80FF80) +#define LCD_COLOR_LIGHTRED ((uint32_t)0xFFFF8080) +#define LCD_COLOR_LIGHTCYAN ((uint32_t)0xFF80FFFF) +#define LCD_COLOR_LIGHTMAGENTA ((uint32_t)0xFFFF80FF) +#define LCD_COLOR_LIGHTYELLOW ((uint32_t)0xFFFFFF80) +#define LCD_COLOR_DARKBLUE ((uint32_t)0xFF000080) +#define LCD_COLOR_DARKGREEN ((uint32_t)0xFF008000) +#define LCD_COLOR_DARKRED ((uint32_t)0xFF800000) +#define LCD_COLOR_DARKCYAN ((uint32_t)0xFF008080) +#define LCD_COLOR_DARKMAGENTA ((uint32_t)0xFF800080) +#define LCD_COLOR_DARKYELLOW ((uint32_t)0xFF808000) +#define LCD_COLOR_WHITE ((uint32_t)0xFFFFFFFF) +#define LCD_COLOR_LIGHTGRAY ((uint32_t)0xFFD3D3D3) +#define LCD_COLOR_GRAY ((uint32_t)0xFF808080) +#define LCD_COLOR_DARKGRAY ((uint32_t)0xFF404040) +#define LCD_COLOR_BLACK ((uint32_t)0xFF000000) +#define LCD_COLOR_BROWN ((uint32_t)0xFFA52A2A) +#define LCD_COLOR_ORANGE ((uint32_t)0xFFFFA500) +#define LCD_COLOR_TRANSPARENT ((uint32_t)0xFF000000) + +/** + * @brief LCD default font + */ +#define LCD_DEFAULT_FONT Font24 + +/** + * @brief LCD Reload Types + */ +#define LCD_RELOAD_IMMEDIATE ((uint32_t)LTDC_SRCR_IMR) +#define LCD_RELOAD_VERTICAL_BLANKING ((uint32_t)LTDC_SRCR_VBR) + +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_LCD_Exported_Functions LCD Exported Functions + * @{ + */ +uint8_t BSP_LCD_Init(void); +uint8_t BSP_LCD_InitEx(uint32_t PclkConfig); + +uint8_t BSP_LCD_DeInit(void); +uint32_t BSP_LCD_GetXSize(void); +uint32_t BSP_LCD_GetYSize(void); +void BSP_LCD_SetXSize(uint32_t imageWidthPixels); +void BSP_LCD_SetYSize(uint32_t imageHeightPixels); + +/* Functions using the LTDC controller */ +void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FrameBuffer); +void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency); +void BSP_LCD_SetTransparency_NoReload(uint32_t LayerIndex, uint8_t Transparency); +void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address); +void BSP_LCD_SetLayerAddress_NoReload(uint32_t LayerIndex, uint32_t Address); +void BSP_LCD_SetColorKeying(uint32_t LayerIndex, uint32_t RGBValue); +void BSP_LCD_SetColorKeying_NoReload(uint32_t LayerIndex, uint32_t RGBValue); +void BSP_LCD_ResetColorKeying(uint32_t LayerIndex); +void BSP_LCD_ResetColorKeying_NoReload(uint32_t LayerIndex); +void BSP_LCD_SetLayerWindow(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_SetLayerWindow_NoReload(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_SelectLayer(uint32_t LayerIndex); +void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState State); +void BSP_LCD_SetLayerVisible_NoReload(uint32_t LayerIndex, FunctionalState State); +void BSP_LCD_Relaod(uint32_t ReloadType); + +void BSP_LCD_SetTextColor(uint32_t Color); +uint32_t BSP_LCD_GetTextColor(void); +void BSP_LCD_SetBackColor(uint32_t Color); +uint32_t BSP_LCD_GetBackColor(void); +void BSP_LCD_SetFont(sFONT *fonts); +sFONT *BSP_LCD_GetFont(void); + +uint32_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos); +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t pixel); +void BSP_LCD_Clear(uint32_t Color); +void BSP_LCD_ClearStringLine(uint32_t Line); +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr); +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode); +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii); + +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius); +void BSP_LCD_DrawBitmap(uint32_t Xpos, uint32_t Ypos, uint8_t *pbmp); + +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius); + +void BSP_LCD_DisplayOff(void); +void BSP_LCD_DisplayOn(void); + +/* These functions can be modified in case the current settings + need to be changed for specific application needs */ +void BSP_LCD_MspInit(LTDC_HandleTypeDef *hltdc, void *Params); +void BSP_LCD_MspDeInit(LTDC_HandleTypeDef *hltdc, void *Params); +void BSP_LCD_ClockConfig(LTDC_HandleTypeDef *hltdc, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32756G_EVAL_LCD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_nor.c b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_nor.c new file mode 100644 index 00000000..1b1d0948 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_nor.c @@ -0,0 +1,456 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_nor.c + * @author MCD Application Team + * @brief This file includes a standard driver for the PC28F128M29EWLA NOR flash memory + * device mounted on STM32756G-EVAL and STM32746G-EVAL evaluation boards. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the PC28F128M29EWLA NOR flash external memory mounted + on STM32756G-EVAL evaluation board. + - This driver does not need a specific component driver for the NOR device + to be included with. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the NOR external memory using the BSP_NOR_Init() function. This + function includes the MSP layer hardware resources initialization and the + FMC controller configuration to interface with the external NOR memory. + + + NOR flash operations + o NOR external memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_NOR_ReadData()/BSP_NOR_WriteData(). The BSP_NOR_WriteData() performs write operation + of an amount of data by unit (halfword). You can also perform a program data + operation of an amount of data using the function BSP_NOR_ProgramData(). + o The function BSP_NOR_Read_ID() returns the chip IDs stored in the structure + "NOR_IDTypeDef". (see the NOR IDs in the memory data sheet) + o Perform erase block operation using the function BSP_NOR_Erase_Block() and by + specifying the block address. You can perform an erase operation of the whole + chip by calling the function BSP_NOR_Erase_Chip(). + o After other operations, the function BSP_NOR_ReturnToReadMode() allows the NOR + flash to return to read mode to perform read operations on it. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_nor.c +- stm32f7xx_ll_fmc.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval_nor.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @defgroup STM32756G_EVAL_NOR STM32756G_EVAL NOR + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ + +/** @defgroup STM32756G_EVAL_NOR_Private_Types_Definitions NOR Private Types Definitions + * @{ + */ +/** + * @} + */ +/* Private define ------------------------------------------------------------*/ + +/** @defgroup STM32756G_EVAL_NOR_Private_Defines NOR Private Defines + * @{ + */ +/** + * @} + */ +/* Private macro -------------------------------------------------------------*/ + +/** @defgroup STM32756G_EVAL_NOR_Private_Macros NOR Private Macros + * @{ + */ +/** + * @} + */ +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup STM32756G_EVAL_NOR_Private_Variables NOR Private Variables + * @{ + */ +static NOR_HandleTypeDef norHandle; +static FMC_NORSRAM_TimingTypeDef Timing; + +/** + * @} + */ + +/* Private function prototypes -----------------------------------------------*/ + +/** @defgroup STM32756G_EVAL_NOR_Private_Functions_Prototypes NOR Private Functions Prototypes + * @{ + */ +/** + * @} + */ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup STM32756G_EVAL_NOR_Private_Functions NOR Private Functions + * @{ + */ + +/** + * @brief Initializes the NOR device. + * @retval NOR memory status + */ +uint8_t BSP_NOR_Init(void) +{ + static uint8_t nor_status = NOR_STATUS_ERROR; + norHandle.Instance = FMC_NORSRAM_DEVICE; + norHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + /* NOR device configuration */ + /* Timing configuration derived from system clock (up to 216Mhz) + for 108Mhz as NOR clock frequency */ + Timing.AddressSetupTime = 9; + Timing.AddressHoldTime = 1; + Timing.DataSetupTime = 5; + Timing.BusTurnAroundDuration = 4; + Timing.CLKDivision = 4; + Timing.DataLatency = 2; + Timing.AccessMode = FMC_ACCESS_MODE_B; + + norHandle.Init.NSBank = FMC_NORSRAM_BANK1; + norHandle.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; + norHandle.Init.MemoryType = FMC_MEMORY_TYPE_NOR; + norHandle.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16; + norHandle.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE; + norHandle.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; + norHandle.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; + norHandle.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; + norHandle.Init.WaitSignal = FMC_WAIT_SIGNAL_ENABLE; + norHandle.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; + norHandle.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_ENABLE; + norHandle.Init.WriteBurst = FMC_WRITE_BURST_DISABLE; + norHandle.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY; + + /* NOR controller initialization */ + BSP_NOR_MspInit(&norHandle, NULL); /* __weak function can be rewritten by the application */ + + if(HAL_NOR_Init(&norHandle, &Timing, &Timing) != HAL_OK) + { + nor_status = NOR_STATUS_ERROR; + } + else + { + nor_status = NOR_STATUS_OK; + } + return nor_status; +} + +/** + * @brief DeInitializes the NOR device. + * @retval NOR status + */ +uint8_t BSP_NOR_DeInit(void) +{ + static uint8_t nor_status = NOR_ERROR; + /* NOR device de-initialization */ + norHandle.Instance = FMC_NORSRAM_DEVICE; + norHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + if(HAL_NOR_DeInit(&norHandle) != HAL_OK) + { + nor_status = NOR_STATUS_ERROR; + } + else + { + nor_status = NOR_STATUS_OK; + } + + /* NOR controller de-initialization */ + BSP_NOR_MspDeInit(&norHandle, NULL); + + return nor_status; +} + +/** + * @brief Reads an amount of data from the NOR device. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of data to read + * @retval NOR memory status + */ +uint8_t BSP_NOR_ReadData(uint32_t uwStartAddress, uint16_t* pData, uint32_t uwDataSize) +{ + if(HAL_NOR_ReadBuffer(&norHandle, NOR_DEVICE_ADDR + uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return NOR_STATUS_ERROR; + } + else + { + return NOR_STATUS_OK; + } +} + +/** + * @brief Returns the NOR memory to read mode. + * @retval None + */ +void BSP_NOR_ReturnToReadMode(void) +{ + HAL_NOR_ReturnToReadMode(&norHandle); +} + +/** + * @brief Writes an amount of data to the NOR device. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of data to write + * @retval NOR memory status + */ +uint8_t BSP_NOR_WriteData(uint32_t uwStartAddress, uint16_t* pData, uint32_t uwDataSize) +{ + uint32_t index = uwDataSize; + + while(index > 0) + { + /* Write data to NOR */ + HAL_NOR_Program(&norHandle, (uint32_t *)(NOR_DEVICE_ADDR + uwStartAddress), pData); + + /* Read NOR device status */ + if(HAL_NOR_GetStatus(&norHandle, NOR_DEVICE_ADDR, PROGRAM_TIMEOUT) != HAL_NOR_STATUS_SUCCESS) + { + return NOR_STATUS_ERROR; + } + + /* Update the counters */ + index--; + uwStartAddress += 2; + pData++; + } + + return NOR_STATUS_OK; +} + +/** + * @brief Programs an amount of data to the NOR device. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of data to write + * @retval NOR memory status + */ +uint8_t BSP_NOR_ProgramData(uint32_t uwStartAddress, uint16_t* pData, uint32_t uwDataSize) +{ + /* Send NOR program buffer operation */ + HAL_NOR_ProgramBuffer(&norHandle, uwStartAddress, pData, uwDataSize); + + /* Return the NOR memory status */ + if(HAL_NOR_GetStatus(&norHandle, NOR_DEVICE_ADDR, PROGRAM_TIMEOUT) != HAL_NOR_STATUS_SUCCESS) + { + return NOR_STATUS_ERROR; + } + else + { + return NOR_STATUS_OK; + } +} + +/** + * @brief Erases the specified block of the NOR device. + * @param BlockAddress: Block address to erase + * @retval NOR memory status + */ +uint8_t BSP_NOR_Erase_Block(uint32_t BlockAddress) +{ + /* Send NOR erase block operation */ + HAL_NOR_Erase_Block(&norHandle, BlockAddress, NOR_DEVICE_ADDR); + + /* Return the NOR memory status */ + if(HAL_NOR_GetStatus(&norHandle, NOR_DEVICE_ADDR, BLOCKERASE_TIMEOUT) != HAL_NOR_STATUS_SUCCESS) + { + return NOR_STATUS_ERROR; + } + else + { + return NOR_STATUS_OK; + } +} + +/** + * @brief Erases the entire NOR chip. + * @retval NOR memory status + */ +uint8_t BSP_NOR_Erase_Chip(void) +{ + /* Send NOR Erase chip operation */ + HAL_NOR_Erase_Chip(&norHandle, NOR_DEVICE_ADDR); + + /* Return the NOR memory status */ + if(HAL_NOR_GetStatus(&norHandle, NOR_DEVICE_ADDR, CHIPERASE_TIMEOUT) != HAL_NOR_STATUS_SUCCESS) + { + return NOR_STATUS_ERROR; + } + else + { + return NOR_STATUS_OK; + } +} + +/** + * @brief Reads NOR flash IDs. + * @param pNOR_ID : Pointer to NOR ID structure + * @retval NOR memory status + */ +uint8_t BSP_NOR_Read_ID(NOR_IDTypeDef *pNOR_ID) +{ + if(HAL_NOR_Read_ID(&norHandle, pNOR_ID) != HAL_OK) + { + return NOR_STATUS_ERROR; + } + else + { + return NOR_STATUS_OK; + } +} + +/** + * @brief Initializes the NOR MSP. + * @param hnor: NOR handle + * @param Params + * @retval None + */ +__weak void BSP_NOR_MspInit(NOR_HandleTypeDef *hnor, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable FMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF12_FMC; + + /* GPIOD configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 |\ + GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 |\ + GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOE configuration */ + gpio_init_structure.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 |\ + GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 |\ + GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOF configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOF, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); +} + +/** + * @brief DeInitializes NOR MSP. + * @param hnor: NOR handle + * @param Params + * @retval None + */ +__weak void BSP_NOR_MspDeInit(NOR_HandleTypeDef *hnor, void *Params) +{ + /* GPIO pins clock, FMC clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief NOR BSP Wait for Ready/Busy signal. + * @param hnor: Pointer to NOR handle + * @param Timeout: Timeout duration + * @retval None + */ +void HAL_NOR_MspWait(NOR_HandleTypeDef *hnor, uint32_t Timeout) +{ + uint32_t timeout = Timeout; + + /* Polling on Ready/Busy signal */ + while((HAL_GPIO_ReadPin(NOR_READY_BUSY_GPIO, NOR_READY_BUSY_PIN) != NOR_BUSY_STATE) && (timeout > 0)) + { + timeout--; + } + + timeout = Timeout; + + /* Polling on Ready/Busy signal */ + while((HAL_GPIO_ReadPin(NOR_READY_BUSY_GPIO, NOR_READY_BUSY_PIN) != NOR_READY_STATE) && (timeout > 0)) + { + timeout--; + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_nor.h b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_nor.h new file mode 100644 index 00000000..27fc0fbe --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_nor.h @@ -0,0 +1,151 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_nor.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32756g_eval_nor.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32756G_EVAL_NOR_H +#define __STM32756G_EVAL_NOR_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @addtogroup STM32756G_EVAL_NOR + * @{ + */ + +/** @defgroup STM32756G_EVAL_NOR_Exported_Types NOR Exported Types + * @{ + */ +/** + * @} + */ + +/** + * @brief NOR status structure definition + */ +#define NOR_STATUS_OK ((uint8_t)0x00) +#define NOR_STATUS_ERROR ((uint8_t)0x01) + +/** @defgroup STM32756G_EVAL_NOR_Exported_Constants NOR Exported Constants + * @{ + */ +#define NOR_DEVICE_ADDR ((uint32_t)0x60000000) + +/* #define NOR_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_8 */ +#define NOR_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_16 + +#define NOR_BURSTACCESS FMC_BURST_ACCESS_MODE_DISABLE +/* #define NOR_BURSTACCESS FMC_BURST_ACCESS_MODE_ENABLE*/ + +#define NOR_WRITEBURST FMC_WRITE_BURST_DISABLE +/* #define NOR_WRITEBURST FMC_WRITE_BURST_ENABLE */ + +#define CONTINUOUSCLOCK_FEATURE FMC_CONTINUOUS_CLOCK_SYNC_ONLY +/* #define CONTINUOUSCLOCK_FEATURE FMC_CONTINUOUS_CLOCK_SYNC_ASYNC */ + +/* NOR operations Timeout definitions */ +#define BLOCKERASE_TIMEOUT ((uint32_t)0x00A00000) /* NOR block erase timeout */ +#define CHIPERASE_TIMEOUT ((uint32_t)0x30000000) /* NOR chip erase timeout */ +#define PROGRAM_TIMEOUT ((uint32_t)0x00004400) /* NOR program timeout */ + +/* NOR Ready/Busy signal GPIO definitions */ +#define NOR_READY_BUSY_PIN GPIO_PIN_6 +#define NOR_READY_BUSY_GPIO GPIOD +#define NOR_READY_STATE GPIO_PIN_SET +#define NOR_BUSY_STATE GPIO_PIN_RESET +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_NOR_Exported_Macro NOR Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_NOR_Exported_Functions NOR Exported Functions + * @{ + */ +uint8_t BSP_NOR_Init(void); +uint8_t BSP_NOR_DeInit(void); +uint8_t BSP_NOR_ReadData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_NOR_WriteData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_NOR_ProgramData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_NOR_Erase_Block(uint32_t BlockAddress); +uint8_t BSP_NOR_Erase_Chip(void); +uint8_t BSP_NOR_Read_ID(NOR_IDTypeDef *pNOR_ID); +void BSP_NOR_ReturnToReadMode(void); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_NOR_MspInit(NOR_HandleTypeDef *hnor, void *Params); +void BSP_NOR_MspDeInit(NOR_HandleTypeDef *hnor, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32756G_EVAL_NOR_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_qspi.c b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_qspi.c new file mode 100644 index 00000000..34c6c948 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_qspi.c @@ -0,0 +1,847 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_qspi.c + * @author MCD Application Team + * @brief This file includes a standard driver for the N25Q512A QSPI + * memory mounted on STM32756G-EVAL and STM32746G-EVAL board. + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + (#) This driver is used to drive the N25Q512A QSPI external + memory mounted on STM32756G-EVAL and STM32746G-EVAL evaluation board. + + (#) This driver need a specific component driver (N25Q512A) to be included with. + + (#) Initialization steps: + (++) Initialize the QPSI external memory using the BSP_QSPI_Init() function. This + function includes the MSP layer hardware resources initialization and the + QSPI interface with the external memory. + + (#) QSPI memory operations + (++) QSPI memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_QSPI_Read()/BSP_QSPI_Write(). + (++) The function BSP_QSPI_GetInfo() returns the configuration of the QSPI memory. + (see the QSPI memory data sheet) + (++) Perform erase block operation using the function BSP_QSPI_Erase_Block() and by + specifying the block address. You can perform an erase operation of the whole + chip by calling the function BSP_QSPI_Erase_Chip(). + (++) The function BSP_QSPI_GetStatus() returns the current status of the QSPI memory. + (see the QSPI memory data sheet) + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_qspi.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- n25q512a.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval_qspi.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @defgroup STM32756G_EVAL_QSPI STM32756G-EVAL QSPI + * @{ + */ + + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup STM32756G_EVAL_QSPI_Private_Variables Private Variables + * @{ + */ +QSPI_HandleTypeDef QSPIHandle; + +/** + * @} + */ + + + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup STM32756G_EVAL_QSPI_Private_Functions Private Functions + * @{ + */ +static uint8_t QSPI_ResetMemory (QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_DummyCyclesCfg (QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_WriteEnable (QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout); + +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_QSPI_Exported_Functions Exported Functions + * @{ + */ + +/** + * @brief Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Init(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level initialization */ + BSP_QSPI_MspInit(&QSPIHandle, NULL); + + /* QSPI initialization */ + /* QSPI freq = SYSCLK /(1 + ClockPrescaler) = 216 MHz/(1+1) = 108 Mhz */ + QSPIHandle.Init.ClockPrescaler = 1; + QSPIHandle.Init.FifoThreshold = 4; + QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; + QSPIHandle.Init.FlashSize = POSITION_VAL(N25Q512A_FLASH_SIZE) - 1; + QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE; /* Min 50ns for nonRead */ + QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; + QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1; + QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE; + + if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* QSPI memory reset */ + if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Set the QSPI memory in 4-bytes address mode */ + if (QSPI_EnterFourBytesAddress(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Configuration of the dummy cycles on QSPI memory side */ + if (QSPI_DummyCyclesCfg(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + return QSPI_OK; +} + +/** + * @brief De-Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_DeInit(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level De-initialization */ + BSP_QSPI_MspDeInit(&QSPIHandle, NULL); + + return QSPI_OK; +} + +/** + * @brief Reads an amount of data from the QSPI memory. + * @param pData: Pointer to data to be read + * @param ReadAddr: Read start address + * @param Size: Size of data to read + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the read command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = QUAD_OUT_FAST_READ_CMD; + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.Address = ReadAddr; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = N25Q512A_DUMMY_CYCLES_READ_QUAD; + s_command.NbData = Size; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Set S# timing for Read command */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_3_CYCLE); + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Restore S# timing for nonRead commands */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_6_CYCLE); + + return QSPI_OK; +} + +/** + * @brief Writes an amount of data to the QSPI memory. + * @param pData: Pointer to data to be written + * @param WriteAddr: Write start address + * @param Size: Size of data to write + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + uint32_t end_addr, current_size, current_addr; + + /* Calculation of the size between the write address and the end of the page */ + current_size = N25Q512A_PAGE_SIZE - (WriteAddr % N25Q512A_PAGE_SIZE); + + /* Check if the size of the data is less than the remaining place in the page */ + if (current_size > Size) + { + current_size = Size; + } + + /* Initialize the address variables */ + current_addr = WriteAddr; + end_addr = WriteAddr + Size; + + /* Initialize the program command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = QUAD_IN_FAST_PROG_CMD; + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Perform the write page by page */ + do + { + s_command.Address = current_addr; + s_command.NbData = current_size; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of program */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update the address and size variables for next page programming */ + current_addr += current_size; + pData += current_size; + current_size = ((current_addr + N25Q512A_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : N25Q512A_PAGE_SIZE; + } while (current_addr < end_addr); + + return QSPI_OK; +} + +/** + * @brief Erases the specified block of the QSPI memory. + * @param BlockAddress: Block address to erase + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = SUBSECTOR_ERASE_CMD; + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.Address = BlockAddress; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, N25Q512A_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Erases the entire QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Chip(void) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = BULK_ERASE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, N25Q512A_BULK_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Reads current status of the QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetStatus(void) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg; + + /* Initialize the read flag status register command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_FLAG_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Check the value of the register */ + if ((reg & (N25Q512A_FSR_PRERR | N25Q512A_FSR_VPPERR | N25Q512A_FSR_PGERR | N25Q512A_FSR_ERERR)) != 0) + { + return QSPI_ERROR; + } + else if ((reg & (N25Q512A_FSR_PGSUS | N25Q512A_FSR_ERSUS)) != 0) + { + return QSPI_SUSPENDED; + } + else if ((reg & N25Q512A_FSR_READY) != 0) + { + return QSPI_OK; + } + else + { + return QSPI_BUSY; + } +} + +/** + * @brief Return the configuration of the QSPI memory. + * @param pInfo: pointer on the configuration structure + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetInfo(QSPI_Info* pInfo) +{ + /* Configure the structure with the memory configuration */ + pInfo->FlashSize = N25Q512A_FLASH_SIZE; + pInfo->EraseSectorSize = N25Q512A_SUBSECTOR_SIZE; + pInfo->EraseSectorsNumber = (N25Q512A_FLASH_SIZE/N25Q512A_SUBSECTOR_SIZE); + pInfo->ProgPageSize = N25Q512A_PAGE_SIZE; + pInfo->ProgPagesNumber = (N25Q512A_FLASH_SIZE/N25Q512A_PAGE_SIZE); + + return QSPI_OK; +} + +/** + * @brief Configure the QSPI in memory-mapped mode + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_EnableMemoryMappedMode(void) +{ + QSPI_CommandTypeDef s_command; + QSPI_MemoryMappedTypeDef s_mem_mapped_cfg; + + /* Configure the command for the read instruction */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = QUAD_OUT_FAST_READ_CMD; + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = N25Q512A_DUMMY_CYCLES_READ_QUAD; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the memory mapped mode */ + s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; + s_mem_mapped_cfg.TimeOutPeriod = 0; + + if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @} + */ + +/** @addtogroup STM32756G_EVAL_QSPI_Private_Functions + * @{ + */ + +/** + * @brief QSPI MSP Initialization + * This function configures the hardware resources used in this example: + * - Peripheral's clock enable + * - Peripheral's GPIO Configuration + * - NVIC configuration for QSPI interrupt + * @retval None + */ +__weak void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /*##-1- Enable peripherals and GPIO Clocks #################################*/ + /* Enable the QuadSPI memory interface clock */ + QSPI_CLK_ENABLE(); + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + /* Enable GPIO clocks */ + QSPI_CS_GPIO_CLK_ENABLE(); + QSPI_CLK_GPIO_CLK_ENABLE(); + QSPI_D0_GPIO_CLK_ENABLE(); + QSPI_D1_GPIO_CLK_ENABLE(); + QSPI_D2_GPIO_CLK_ENABLE(); + QSPI_D3_GPIO_CLK_ENABLE(); + + /*##-2- Configure peripheral GPIO ##########################################*/ + /* QSPI CS GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CS_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF10_QUADSPI; + HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &gpio_init_structure); + + /* QSPI CLK GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CLK_PIN; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &gpio_init_structure); + + /* QSPI D0 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D0_PIN; + gpio_init_structure.Alternate = GPIO_AF10_QUADSPI; + HAL_GPIO_Init(QSPI_D0_GPIO_PORT, &gpio_init_structure); + + /* QSPI D1 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D1_PIN; + gpio_init_structure.Alternate = GPIO_AF10_QUADSPI; + HAL_GPIO_Init(QSPI_D1_GPIO_PORT, &gpio_init_structure); + + /* QSPI D2 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D2_PIN; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_D2_GPIO_PORT, &gpio_init_structure); + + /* QSPI D3 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D3_PIN; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_D3_GPIO_PORT, &gpio_init_structure); + + /*##-3- Configure the NVIC for QSPI #########################################*/ + /* NVIC configuration for QSPI interrupt */ + HAL_NVIC_SetPriority(QUADSPI_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(QUADSPI_IRQn); +} + +/** + * @brief QSPI MSP De-Initialization + * This function frees the hardware resources used in this example: + * - Disable the Peripheral's clock + * - Revert GPIO and NVIC configuration to their default state + * @retval None + */ +__weak void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + /*##-1- Disable the NVIC for QSPI ###########################################*/ + HAL_NVIC_DisableIRQ(QUADSPI_IRQn); + + /*##-2- Disable peripherals and GPIO Clocks ################################*/ + /* De-Configure QSPI pins */ + HAL_GPIO_DeInit(QSPI_CS_GPIO_PORT, QSPI_CS_PIN); + HAL_GPIO_DeInit(QSPI_CLK_GPIO_PORT, QSPI_CLK_PIN); + HAL_GPIO_DeInit(QSPI_D0_GPIO_PORT, QSPI_D0_PIN); + HAL_GPIO_DeInit(QSPI_D1_GPIO_PORT, QSPI_D1_PIN); + HAL_GPIO_DeInit(QSPI_D2_GPIO_PORT, QSPI_D2_PIN); + HAL_GPIO_DeInit(QSPI_D3_GPIO_PORT, QSPI_D3_PIN); + + /*##-3- Reset peripherals ##################################################*/ + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + + /* Disable the QuadSPI memory interface clock */ + QSPI_CLK_DISABLE(); +} + +/** + * @brief This function reset the QSPI memory. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the reset enable command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = RESET_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Send the reset memory command */ + s_command.Instruction = RESET_MEMORY_CMD; + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait the memory is ready */ + if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function set the QSPI memory in 4-byte address mode + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = ENTER_4_BYTE_ADDR_MODE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(hqspi) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait the memory is ready */ + if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function configure the dummy cycles on memory side. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg; + + /* Initialize the read volatile configuration register command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_VOL_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations */ + if (QSPI_WriteEnable(hqspi) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update volatile configuration register (with new dummy cycles) */ + s_command.Instruction = WRITE_VOL_CFG_REG_CMD; + MODIFY_REG(reg, N25Q512A_VCR_NB_DUMMY, (N25Q512A_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(N25Q512A_VCR_NB_DUMMY))); + + /* Configure the write volatile configuration register command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function send a Write Enable and wait it is effective. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Enable write operations */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = WRITE_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for write enabling */ + s_config.Match = N25Q512A_SR_WREN; + s_config.Mask = N25Q512A_SR_WREN; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_1_LINE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function read the SR of the memory and wait the EOP. + * @param hqspi: QSPI handle + * @param Timeout + * @retval None + */ +static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Configure automatic polling mode to wait for memory ready */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + s_config.Match = 0; + s_config.Mask = N25Q512A_SR_WIP; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, Timeout) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_qspi.h b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_qspi.h new file mode 100644 index 00000000..ae6ad5c4 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_qspi.h @@ -0,0 +1,170 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_qspi.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32756g_eval_qspi.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32756G_EVAL_QSPI_H +#define __STM32756G_EVAL_QSPI_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" +#include "../Components/n25q512a/n25q512a.h" + +/** @addtogroup STM32756G_EVAL_QSPI + * @{ + */ + + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup STM32756G_EVAL_QSPI_Exported_Constants Exported Constants + * @{ + */ +/* QSPI Error codes */ +#define QSPI_OK ((uint8_t)0x00) +#define QSPI_ERROR ((uint8_t)0x01) +#define QSPI_BUSY ((uint8_t)0x02) +#define QSPI_NOT_SUPPORTED ((uint8_t)0x04) +#define QSPI_SUSPENDED ((uint8_t)0x08) + + +/* Definition for QSPI clock resources */ +#define QSPI_CLK_ENABLE() __HAL_RCC_QSPI_CLK_ENABLE() +#define QSPI_CLK_DISABLE() __HAL_RCC_QSPI_CLK_DISABLE() +#define QSPI_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_CLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_D0_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() +#define QSPI_D1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() +#define QSPI_D2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() +#define QSPI_D3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() + +#define QSPI_FORCE_RESET() __HAL_RCC_QSPI_FORCE_RESET() +#define QSPI_RELEASE_RESET() __HAL_RCC_QSPI_RELEASE_RESET() + +/* Definition for QSPI Pins */ +#define QSPI_CS_PIN GPIO_PIN_6 +#define QSPI_CS_GPIO_PORT GPIOB +#define QSPI_CLK_PIN GPIO_PIN_2 +#define QSPI_CLK_GPIO_PORT GPIOB +#define QSPI_D0_PIN GPIO_PIN_8 +#define QSPI_D0_GPIO_PORT GPIOF +#define QSPI_D1_PIN GPIO_PIN_9 +#define QSPI_D1_GPIO_PORT GPIOF +#define QSPI_D2_PIN GPIO_PIN_7 +#define QSPI_D2_GPIO_PORT GPIOF +#define QSPI_D3_PIN GPIO_PIN_6 +#define QSPI_D3_GPIO_PORT GPIOF + +/* N25Q512A13GSF40E Micron memory */ +/* Size of the flash */ +#define QSPI_FLASH_SIZE 25 /* Address bus width to access whole memory space */ +#define QSPI_PAGE_SIZE 256 + +/* This alias is added as the name of Memory mapped fucntion changed */ +#define BSP_QSPI_MemoryMappedMode BSP_QSPI_EnableMemoryMappedMode +/** + * @} + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup STM32756G_EVAL_QSPI_Exported_Types Exported Types + * @{ + */ +/* QSPI Info */ +typedef struct { + uint32_t FlashSize; /*!< Size of the flash */ + uint32_t EraseSectorSize; /*!< Size of sectors for the erase operation */ + uint32_t EraseSectorsNumber; /*!< Number of sectors for the erase operation */ + uint32_t ProgPageSize; /*!< Size of pages for the program operation */ + uint32_t ProgPagesNumber; /*!< Number of pages for the program operation */ +} QSPI_Info; + +/** + * @} + */ + + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup STM32756G_EVAL_QSPI_Exported_Functions + * @{ + */ +uint8_t BSP_QSPI_Init (void); +uint8_t BSP_QSPI_DeInit (void); +uint8_t BSP_QSPI_Read (uint8_t* pData, uint32_t ReadAddr, uint32_t Size); +uint8_t BSP_QSPI_Write (uint8_t* pData, uint32_t WriteAddr, uint32_t Size); +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress); +uint8_t BSP_QSPI_Erase_Chip (void); +uint8_t BSP_QSPI_GetStatus (void); +uint8_t BSP_QSPI_GetInfo (QSPI_Info* pInfo); +uint8_t BSP_QSPI_EnableMemoryMappedMode(void); + +/* These functions can be modified in case the current settings + need to be changed for specific application needs */ +void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params); +void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32756G_EVAL_QSPI_H */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sd.c b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sd.c new file mode 100644 index 00000000..b6366b72 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sd.c @@ -0,0 +1,612 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_sd.c + * @author MCD Application Team + * @brief This file includes the uSD card driver mounted on STM32756G-EVAL and + * STM32746G-EVAL evaluation boards. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the micro SD external card mounted on STM32756G-EVAL + evaluation board. + - This driver does not need a specific component driver for the micro SD device + to be included with. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the micro SD card using the BSP_SD_Init() function. This + function includes the MSP layer hardware resources initialization and the + SDIO interface configuration to interface with the external micro SD. It + also includes the micro SD initialization sequence. + o To check the SD card presence you can use the function BSP_SD_IsDetected() which + returns the detection status + o If SD presence detection interrupt mode is desired, you must configure the + SD detection interrupt mode by calling the function BSP_SD_ITConfig(). The interrupt + is generated as an external interrupt whenever the micro SD card is + plugged/unplugged in/from the evaluation board. The SD detection is managed by MFX, + so the SD detection interrupt has to be treated by MFX_IRQOUT gpio pin IRQ handler. + o The function BSP_SD_GetCardInfo() is used to get the micro SD card information + which is stored in the structure "HAL_SD_CardInfoTypedef". + + + Micro SD card operations + o The micro SD card can be accessed with read/write block(s) operations once + it is ready for access. The access can be performed whether using the polling + mode by calling the functions BSP_SD_ReadBlocks()/BSP_SD_WriteBlocks(), or by DMA + transfer using the functions BSP_SD_ReadBlocks_DMA()/BSP_SD_WriteBlocks_DMA() + o The DMA transfer complete is used with interrupt mode. Once the SD transfer + is complete, the SD interrupt is handled using the function BSP_SD_IRQHandler(), + the DMA Tx/Rx transfer complete are handled using the functions + BSP_SD_DMA_Tx_IRQHandler()/BSP_SD_DMA_Rx_IRQHandler(). The corresponding user callbacks + are implemented by the user at application level. + o The SD erase block(s) is performed using the function BSP_SD_Erase() with specifying + the number of blocks to erase. + o The SD runtime status is returned when calling the function BSP_SD_GetCardState(). + + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32756g_eval.c +- stm32f7xx_hal_sd.c +- stm32f7xx_ll_sdmmc.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval_sd.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @defgroup STM32756G_EVAL_SD STM32756G_EVAL SD + * @{ + */ + + +/** @defgroup STM32756G_EVAL_SD_Private_TypesDefinitions SD Private TypesDefinitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SD_Private_Defines SD Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SD_Private_Macros SD Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SD_Private_Variables SD Private Variables + * @{ + */ +SD_HandleTypeDef uSdHandle; +static uint8_t UseExtiModeDetection = 0; + +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SD_Private_FunctionPrototypes SD Private Functions Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SD_Private_Functions SD Private Functions + * @{ + */ + +/** + * @brief Initializes the SD card device. + * @retval SD status + */ +uint8_t BSP_SD_Init(void) +{ + uint8_t sd_state = MSD_OK; + + /* uSD device interface configuration */ + uSdHandle.Instance = SDMMC1; + + uSdHandle.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + uSdHandle.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE; + uSdHandle.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; + uSdHandle.Init.BusWide = SDMMC_BUS_WIDE_1B; + uSdHandle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + uSdHandle.Init.ClockDiv = SDMMC_TRANSFER_CLK_DIV; + + /* Initialize IO functionalities (MFX) used by SD detect pin */ + BSP_IO_Init(); + + /* Check if the SD card is plugged in the slot */ + BSP_IO_ConfigPin(SD_DETECT_PIN, IO_MODE_INPUT_PU); + if(BSP_SD_IsDetected() != SD_PRESENT) + { + return MSD_ERROR_SD_NOT_PRESENT; + } + + /* Msp SD initialization */ + BSP_SD_MspInit(&uSdHandle, NULL); + + /* HAL SD initialization */ + if(HAL_SD_Init(&uSdHandle) != MSD_OK) + { + sd_state = MSD_ERROR; + } + + /* Configure SD Bus width */ + if(sd_state == MSD_OK) + { + /* Enable wide operation */ + if(HAL_SD_ConfigWideBusOperation(&uSdHandle, SDMMC_BUS_WIDE_4B) != HAL_OK) + { + sd_state = MSD_ERROR; + } + else + { + sd_state = MSD_OK; + } + } + + return sd_state; +} + +/** + * @brief DeInitializes the SD card device. + * @retval SD status + */ +uint8_t BSP_SD_DeInit(void) +{ + uint8_t sd_state = MSD_OK; + + uSdHandle.Instance = SDMMC1; + + /* Set back Mfx pin to INPUT mode in case it was in exti */ + UseExtiModeDetection = 0; + BSP_IO_ConfigPin(SD_DETECT_PIN, IO_MODE_INPUT_PU); + + /* HAL SD deinitialization */ + if(HAL_SD_DeInit(&uSdHandle) != HAL_OK) + { + sd_state = MSD_ERROR; + } + + /* Msp SD deinitialization */ + uSdHandle.Instance = SDMMC1; + BSP_SD_MspDeInit(&uSdHandle, NULL); + + return sd_state; +} + +/** + * @brief Configures Interrupt mode for SD detection pin. + * @retval Returns 0 + */ +uint8_t BSP_SD_ITConfig(void) +{ + /* Configure Interrupt mode for SD detection pin */ + /* Note: disabling exti mode can be done calling SD_DeInit() */ + UseExtiModeDetection = 1; + BSP_SD_IsDetected(); + + return 0; +} + +/** + * @brief Detects if SD card is correctly plugged in the memory slot or not. + * @retval Returns if SD is detected or not + */ +uint8_t BSP_SD_IsDetected(void) +{ + __IO uint8_t status = SD_PRESENT; + + /* Check SD card detect pin */ + if((BSP_IO_ReadPin(SD_DETECT_PIN)&SD_DETECT_PIN) != SD_DETECT_PIN) + { + if (UseExtiModeDetection) + { + BSP_IO_ConfigPin(SD_DETECT_PIN, IO_MODE_IT_RISING_EDGE_PU); + } + } + else + { + status = SD_NOT_PRESENT; + if (UseExtiModeDetection) + { + BSP_IO_ConfigPin(SD_DETECT_PIN, IO_MODE_IT_FALLING_EDGE_PU); + } + } + return status; +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @param Timeout: Timeout for read operation + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + if(HAL_SD_ReadBlocks(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks, Timeout) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @param Timeout: Timeout for write operation + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + if(HAL_SD_WriteBlocks(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks, Timeout) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in DMA mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks) +{ + /* Read block(s) in DMA transfer mode */ + if(HAL_SD_ReadBlocks_DMA(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in DMA mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks) +{ + /* Write block(s) in DMA transfer mode */ + if(HAL_SD_WriteBlocks_DMA(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Erases the specified memory area of the given SD card. + * @param StartAddr: Start byte address + * @param EndAddr: End byte address + * @retval SD status + */ +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr) +{ + if(HAL_SD_Erase(&uSdHandle, StartAddr, EndAddr) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Initializes the SD MSP. + * @param hsd: SD handle + * @param Params + * @retval None + */ +__weak void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params) +{ + static DMA_HandleTypeDef dma_rx_handle; + static DMA_HandleTypeDef dma_tx_handle; + GPIO_InitTypeDef gpio_init_structure; + + /* Camera has to be powered down as some signals use same GPIOs between + * SD card and camera bus. Camera drives its signals to low impedance + * when powered ON. So the camera is powered off to let its signals + * in high impedance */ + + /* Camera power down sequence */ + BSP_IO_ConfigPin(RSTI_PIN, IO_MODE_OUTPUT); + BSP_IO_ConfigPin(XSDN_PIN, IO_MODE_OUTPUT); + /* De-assert the camera STANDBY pin (active high) */ + BSP_IO_WritePin(XSDN_PIN, BSP_IO_PIN_RESET); + /* Assert the camera RSTI pin (active low) */ + BSP_IO_WritePin(RSTI_PIN, BSP_IO_PIN_RESET); + + /* Enable SDIO clock */ + __HAL_RCC_SDMMC1_CLK_ENABLE(); + + /* Enable DMA2 clocks */ + __DMAx_TxRx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF12_SDMMC1; + + /* GPIOC configuration */ + gpio_init_structure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; + + HAL_GPIO_Init(GPIOC, &gpio_init_structure); + + /* GPIOD configuration */ + gpio_init_structure.Pin = GPIO_PIN_2; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* NVIC configuration for SDIO interrupts */ + HAL_NVIC_SetPriority(SDMMC1_IRQn, 0x0E, 0); + HAL_NVIC_EnableIRQ(SDMMC1_IRQn); + + /* Configure DMA Rx parameters */ + dma_rx_handle.Init.Channel = SD_DMAx_Rx_CHANNEL; + dma_rx_handle.Init.Direction = DMA_PERIPH_TO_MEMORY; + dma_rx_handle.Init.PeriphInc = DMA_PINC_DISABLE; + dma_rx_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_rx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_rx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_rx_handle.Init.Mode = DMA_PFCTRL; + dma_rx_handle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + dma_rx_handle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + dma_rx_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_rx_handle.Init.MemBurst = DMA_MBURST_INC4; + dma_rx_handle.Init.PeriphBurst = DMA_PBURST_INC4; + + dma_rx_handle.Instance = SD_DMAx_Rx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsd, hdmarx, dma_rx_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_rx_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_rx_handle); + + /* Configure DMA Tx parameters */ + dma_tx_handle.Init.Channel = SD_DMAx_Tx_CHANNEL; + dma_tx_handle.Init.Direction = DMA_MEMORY_TO_PERIPH; + dma_tx_handle.Init.PeriphInc = DMA_PINC_DISABLE; + dma_tx_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_tx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_tx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_tx_handle.Init.Mode = DMA_PFCTRL; + dma_tx_handle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + dma_tx_handle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + dma_tx_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_tx_handle.Init.MemBurst = DMA_MBURST_INC4; + dma_tx_handle.Init.PeriphBurst = DMA_PBURST_INC4; + + dma_tx_handle.Instance = SD_DMAx_Tx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsd, hdmatx, dma_tx_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_tx_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_tx_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD_DMAx_Rx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SD_DMAx_Rx_IRQn); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD_DMAx_Tx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SD_DMAx_Tx_IRQn); +} + +/** + * @brief DeInitializes the SD MSP. + * @param hsd: SD handle + * @param Params + * @retval None + */ +__weak void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params) +{ + static DMA_HandleTypeDef dma_rx_handle; + static DMA_HandleTypeDef dma_tx_handle; + + /* Disable NVIC for DMA transfer complete interrupts */ + HAL_NVIC_DisableIRQ(SD_DMAx_Rx_IRQn); + HAL_NVIC_DisableIRQ(SD_DMAx_Tx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_rx_handle.Instance = SD_DMAx_Rx_STREAM; + HAL_DMA_DeInit(&dma_rx_handle); + + /* Deinitialize the stream for new transfer */ + dma_tx_handle.Instance = SD_DMAx_Tx_STREAM; + HAL_DMA_DeInit(&dma_tx_handle); + + /* Disable NVIC for SDIO interrupts */ + HAL_NVIC_DisableIRQ(SDMMC1_IRQn); + + /* DeInit GPIO pins can be done in the application + (by surcharging this __weak function) */ + + /* Disable SDMMC1 clock */ + __HAL_RCC_SDMMC1_CLK_DISABLE(); + + /* GPIO pins clock and DMA clocks can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Gets the current SD card data status. + * @retval Data transfer state. + * This value can be one of the following values: + * @arg SD_TRANSFER_OK: No data transfer is acting + * @arg SD_TRANSFER_BUSY: Data transfer is acting + */ +uint8_t BSP_SD_GetCardState(void) +{ + return((HAL_SD_GetCardState(&uSdHandle) == HAL_SD_CARD_TRANSFER ) ? SD_TRANSFER_OK : SD_TRANSFER_BUSY); +} + + +/** + * @brief Get SD information about specific SD card. + * @param CardInfo: Pointer to HAL_SD_CardInfoTypedef structure + * @retval None + */ +void BSP_SD_GetCardInfo(HAL_SD_CardInfoTypeDef *CardInfo) +{ + /* Get SD card Information */ + HAL_SD_GetCardInfo(&uSdHandle, CardInfo); +} + +/** + * @brief SD Abort callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_AbortCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_AbortCallback(); +} + +/** + * @brief Tx Transfer completed callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_WriteCpltCallback(); +} + +/** + * @brief Rx Transfer completed callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_ReadCpltCallback(); +} + +/** + * @brief BSP SD Abort callbacks + * @retval None + */ +__weak void BSP_SD_AbortCallback(void) +{ + +} + +/** + * @brief BSP Tx Transfer completed callbacks + * @retval None + */ +__weak void BSP_SD_WriteCpltCallback(void) +{ + +} + +/** + * @brief BSP Rx Transfer completed callbacks + * @retval None + */ +__weak void BSP_SD_ReadCpltCallback(void) +{ + +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sd.h b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sd.h new file mode 100644 index 00000000..da6d25f7 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sd.h @@ -0,0 +1,163 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_sd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32756g_eval_sd.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32756G_EVAL_SD_H +#define __STM32756G_EVAL_SD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" +#include "stm32756g_eval_io.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @addtogroup STM32756G_EVAL_SD + * @{ + */ + +/** @defgroup STM32756G_EVAL_SD_Exported_Types SD Exported Types + * @{ + */ + +/** + * @brief SD Card information structure + */ +#define BSP_SD_CardInfo HAL_SD_CardInfoTypeDef +/** + * @} + */ + +/** + * @brief SD status structure definition + */ +#define MSD_OK ((uint8_t)0x00) +#define MSD_ERROR ((uint8_t)0x01) +#define MSD_ERROR_SD_NOT_PRESENT ((uint8_t)0x02) + +/** + * @brief SD transfer state definition + */ +#define SD_TRANSFER_OK ((uint8_t)0x00) +#define SD_TRANSFER_BUSY ((uint8_t)0x01) + +/** @defgroup STM32756G_EVAL_SD_Exported_Constants SD Exported Constants + * @{ + */ +#define SD_PRESENT ((uint8_t)0x01) +#define SD_NOT_PRESENT ((uint8_t)0x00) + +#define SD_DATATIMEOUT ((uint32_t)100000000) + +/* DMA definitions for SD DMA transfer */ +#define __DMAx_TxRx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define SD_DMAx_Tx_CHANNEL DMA_CHANNEL_4 +#define SD_DMAx_Rx_CHANNEL DMA_CHANNEL_4 +#define SD_DMAx_Tx_STREAM DMA2_Stream6 +#define SD_DMAx_Rx_STREAM DMA2_Stream3 +#define SD_DMAx_Tx_IRQn DMA2_Stream6_IRQn +#define SD_DMAx_Rx_IRQn DMA2_Stream3_IRQn +#define BSP_SDMMC_IRQHandler SDMMC1_IRQHandler +#define BSP_SDMMC_DMA_Tx_IRQHandler DMA2_Stream6_IRQHandler +#define BSP_SDMMC_DMA_Rx_IRQHandler DMA2_Stream3_IRQHandler +#define SD_DetectIRQHandler() HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_8) +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SD_Exported_Macro SD Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SD_Exported_Functions SD Exported Functions + * @{ + */ +uint8_t BSP_SD_Init(void); +uint8_t BSP_SD_DeInit(void); +uint8_t BSP_SD_ITConfig(void); +void BSP_SD_DetectIT(void); +void BSP_SD_DetectCallback(void); +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks); +uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks); +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); +uint8_t BSP_SD_GetCardState(void); +void BSP_SD_GetCardInfo(BSP_SD_CardInfo *CardInfo); +uint8_t BSP_SD_IsDetected(void); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_AbortCallback(void); +void BSP_SD_WriteCpltCallback(void); +void BSP_SD_ReadCpltCallback(void); +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32756G_EVAL_SD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sdram.c b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sdram.c new file mode 100644 index 00000000..f30a48f2 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sdram.c @@ -0,0 +1,504 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_sdram.c + * @author MCD Application Team + * @brief This file includes the SDRAM driver for the MT48LC4M32B2B5-7 memory + * device mounted on STM32756G-EVAL and STM32746G-EVAL evaluation boards. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the MT48LC4M32B2B5-7 SDRAM external memory mounted + on STM32756G-EVAL evaluation board. + - This driver does not need a specific component driver for the SDRAM device + to be included with. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the SDRAM external memory using the BSP_SDRAM_Init() function. This + function includes the MSP layer hardware resources initialization and the + FMC controller configuration to interface with the external SDRAM memory. + o It contains the SDRAM initialization sequence to program the SDRAM external + device using the function BSP_SDRAM_Initialization_sequence(). Note that this + sequence is standard for all SDRAM devices, but can include some differences + from a device to another. If it is the case, the right sequence should be + implemented separately. + + + SDRAM read/write operations + o SDRAM external memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_SDRAM_ReadData()/BSP_SDRAM_WriteData(), or by DMA transfer using the functions + BSP_SDRAM_ReadData_DMA()/BSP_SDRAM_WriteData_DMA(). + o The AHB access is performed with 32-bit width transaction, the DMA transfer + configuration is fixed at single (no burst) word transfer (see the + SDRAM_MspInit() static function). + o User can implement his own functions for read/write access with his desired + configurations. + o If interrupt mode is used for DMA transfer, the function BSP_SDRAM_DMA_IRQHandler() + is called in IRQ handler file, to serve the generated interrupt once the DMA + transfer is complete. + o You can send a command to the SDRAM device in runtime using the function + BSP_SDRAM_Sendcmd(), and giving the desired command as parameter chosen between + the predefined commands of the "FMC_SDRAM_CommandTypeDef" structure. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_sdram.c +- stm32f7xx_ll_fmc.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval_sdram.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @defgroup STM32756G_EVAL_SDRAM STM32756G_EVAL SDRAM + * @{ + */ + +/** @defgroup STM32756G_EVAL_SDRAM_Private_Types_Definitions SDRAM Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SDRAM_Private_Defines SDRAM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SDRAM_Private_Macros SDRAM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SDRAM_Private_Variables SDRAM Private Variables + * @{ + */ +SDRAM_HandleTypeDef sdramHandle; +static FMC_SDRAM_TimingTypeDef Timing; +static FMC_SDRAM_CommandTypeDef Command; +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SDRAM_Private_Functions_Prototypes SDRAM Private Functions Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SDRAM_Private_Functions SDRAM Private Functions + * @{ + */ + +/** + * @brief Initializes the SDRAM device. + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_Init(void) +{ + static uint8_t sdramstatus = SDRAM_ERROR; + /* SDRAM device configuration */ + sdramHandle.Instance = FMC_SDRAM_DEVICE; + + /* Timing configuration for 100Mhz as SDRAM clock frequency (System clock is up to 200Mhz) */ + Timing.LoadToActiveDelay = 2; + Timing.ExitSelfRefreshDelay = 7; + Timing.SelfRefreshTime = 4; + Timing.RowCycleDelay = 7; + Timing.WriteRecoveryTime = 2; + Timing.RPDelay = 2; + Timing.RCDDelay = 2; + + sdramHandle.Init.SDBank = FMC_SDRAM_BANK1; + sdramHandle.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9; + sdramHandle.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; + sdramHandle.Init.MemoryDataWidth = SDRAM_MEMORY_WIDTH; + sdramHandle.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; + sdramHandle.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3; + sdramHandle.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; + sdramHandle.Init.SDClockPeriod = SDCLOCK_PERIOD; + sdramHandle.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE; + sdramHandle.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; + + /* SDRAM controller initialization */ + + BSP_SDRAM_MspInit(&sdramHandle, NULL); /* __weak function can be rewritten by the application */ + + if(HAL_SDRAM_Init(&sdramHandle, &Timing) != HAL_OK) + { + sdramstatus = SDRAM_ERROR; + } + else + { + sdramstatus = SDRAM_OK; + } + + /* SDRAM initialization sequence */ + BSP_SDRAM_Initialization_sequence(REFRESH_COUNT); + + return sdramstatus; +} + +/** + * @brief DeInitializes the SDRAM device. + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_DeInit(void) +{ + static uint8_t sdramstatus = SDRAM_ERROR; + /* SDRAM device de-initialization */ + sdramHandle.Instance = FMC_SDRAM_DEVICE; + + if(HAL_SDRAM_DeInit(&sdramHandle) != HAL_OK) + { + sdramstatus = SDRAM_ERROR; + } + else + { + sdramstatus = SDRAM_OK; + } + + /* SDRAM controller de-initialization */ + BSP_SDRAM_MspDeInit(&sdramHandle, NULL); + + return sdramstatus; +} + +/** + * @brief Programs the SDRAM device. + * @param RefreshCount: SDRAM refresh counter value + * @retval None + */ +void BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount) +{ + __IO uint32_t tmpmrd = 0; + + /* Step 1: Configure a clock configuration enable command */ + Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 2: Insert 100 us minimum delay */ + /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */ + HAL_Delay(1); + + /* Step 3: Configure a PALL (precharge all) command */ + Command.CommandMode = FMC_SDRAM_CMD_PALL; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 4: Configure an Auto Refresh command */ + Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 8; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 5: Program the external memory mode register */ + tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |\ + SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |\ + SDRAM_MODEREG_CAS_LATENCY_3 |\ + SDRAM_MODEREG_OPERATING_MODE_STANDARD |\ + SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; + + Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = tmpmrd; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 6: Set the refresh rate counter */ + /* Set the device refresh rate */ + HAL_SDRAM_ProgramRefreshRate(&sdramHandle, RefreshCount); +} + +/** + * @brief Reads an amount of data from the SDRAM memory in polling mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_ReadData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Read_32b(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Reads an amount of data from the SDRAM memory in DMA mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_ReadData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Read_DMA(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Writes an amount of data to the SDRAM memory in polling mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_WriteData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Write_32b(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Writes an amount of data to the SDRAM memory in DMA mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_WriteData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Write_DMA(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Sends command to the SDRAM bank. + * @param SdramCmd: Pointer to SDRAM command structure + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_Sendcmd(FMC_SDRAM_CommandTypeDef *SdramCmd) +{ + if(HAL_SDRAM_SendCommand(&sdramHandle, SdramCmd, SDRAM_TIMEOUT) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + + +/** + * @brief Initializes SDRAM MSP. + * @param hsdram: SDRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable FMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + + /* Enable chosen DMAx clock */ + __DMAx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = GPIO_AF12_FMC; + + /* GPIOD configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8| GPIO_PIN_9 | GPIO_PIN_10 |\ + GPIO_PIN_14 | GPIO_PIN_15; + + + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOE configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7| GPIO_PIN_8 | GPIO_PIN_9 |\ + GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\ + GPIO_PIN_15; + + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOF configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\ + GPIO_PIN_15; + + HAL_GPIO_Init(GPIOF, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4| GPIO_PIN_5 | GPIO_PIN_8 |\ + GPIO_PIN_15; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + /* GPIOH configuration */ + gpio_init_structure.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_9 |\ + GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\ + GPIO_PIN_15; + HAL_GPIO_Init(GPIOH, &gpio_init_structure); + + /* GPIOI configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_9 | GPIO_PIN_10; + HAL_GPIO_Init(GPIOI, &gpio_init_structure); + + /* Configure common DMA parameters */ + dma_handle.Init.Channel = SDRAM_DMAx_CHANNEL; + dma_handle.Init.Direction = DMA_MEMORY_TO_MEMORY; + dma_handle.Init.PeriphInc = DMA_PINC_ENABLE; + dma_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_handle.Init.Mode = DMA_NORMAL; + dma_handle.Init.Priority = DMA_PRIORITY_HIGH; + dma_handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + dma_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_handle.Init.MemBurst = DMA_MBURST_SINGLE; + dma_handle.Init.PeriphBurst = DMA_PBURST_SINGLE; + + dma_handle.Instance = SDRAM_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsdram, hdma, dma_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SDRAM_DMAx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SDRAM_DMAx_IRQn); +} + +/** + * @brief DeInitializes SDRAM MSP. + * @param hsdram: SDRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SDRAM_MspDeInit(SDRAM_HandleTypeDef *hsdram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + + /* Disable NVIC configuration for DMA interrupt */ + HAL_NVIC_DisableIRQ(SDRAM_DMAx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_handle.Instance = SDRAM_DMAx_STREAM; + HAL_DMA_DeInit(&dma_handle); + + /* GPIO pins clock, FMC clock and DMA clock can be shut down in the applications + by surcharging this __weak function */ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sdram.h b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sdram.h new file mode 100644 index 00000000..c73ae18f --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sdram.h @@ -0,0 +1,163 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_sdram.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32756g_eval_sdram.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32756G_EVAL_SDRAM_H +#define __STM32756G_EVAL_SDRAM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @addtogroup STM32756G_EVAL_SDRAM + * @{ + */ + +/** @defgroup STM32756G_EVAL_SDRAM_Exported_Types SDRAM Exported Types + * @{ + */ + +/** + * @brief SDRAM status structure definition + */ +#define SDRAM_OK ((uint8_t)0x00) +#define SDRAM_ERROR ((uint8_t)0x01) + +/** @defgroup STM32756G_EVAL_SDRAM_Exported_Constants SDRAM Exported Constants + * @{ + */ +#define SDRAM_DEVICE_ADDR ((uint32_t)0xC0000000) +#define SDRAM_DEVICE_SIZE ((uint32_t)0x800000) /* SDRAM device size in MBytes */ + +/* #define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_8 */ +/* #define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_16 */ +#define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_32 + +#define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_2 +/* #define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_3 */ + +#define REFRESH_COUNT ((uint32_t)0x0603) /* SDRAM refresh counter (100Mhz SD clock) */ + +#define SDRAM_TIMEOUT ((uint32_t)0xFFFF) + +/* DMA definitions for SDRAM DMA transfer */ +#define __DMAx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define __DMAx_CLK_DISABLE __HAL_RCC_DMA2_CLK_DISABLE +#define SDRAM_DMAx_CHANNEL DMA_CHANNEL_0 +#define SDRAM_DMAx_STREAM DMA2_Stream0 +#define SDRAM_DMAx_IRQn DMA2_Stream0_IRQn +#define BSP_SDRAM_DMA_IRQHandler DMA2_Stream0_IRQHandler +/** + * @} + */ + +/** + * @brief FMC SDRAM Mode definition register defines + */ +#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) +#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) +#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) +#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) +#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) +#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) +#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SDRAM_Exported_Macro SDRAM Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SDRAM_Exported_Functions SDRAM Exported Functions + * @{ + */ +uint8_t BSP_SDRAM_Init(void); +uint8_t BSP_SDRAM_DeInit(void); +void BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount); +uint8_t BSP_SDRAM_ReadData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_ReadData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_WriteData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_WriteData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_Sendcmd(FMC_SDRAM_CommandTypeDef *SdramCmd); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram, void *Params); +void BSP_SDRAM_MspDeInit(SDRAM_HandleTypeDef *hsdram, void *Params); + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32756G_EVAL_SDRAM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sram.c b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sram.c new file mode 100644 index 00000000..1ab2055d --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sram.c @@ -0,0 +1,402 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_sram.c + * @author MCD Application Team + * @brief This file includes the SRAM driver for the IS61WV102416BLL-10M memory + * device mounted on STM32756G-EVAL and STM32746G-EVAL evaluation boards. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the IS61WV102416BLL-10M SRAM external memory mounted + on STM32756G-EVAL evaluation board. + - This driver does not need a specific component driver for the SRAM device + to be included with. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the SRAM external memory using the BSP_SRAM_Init() function. This + function includes the MSP layer hardware resources initialization and the + FMC controller configuration to interface with the external SRAM memory. + + + SRAM read/write operations + o SRAM external memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_SRAM_ReadData()/BSP_SRAM_WriteData(), or by DMA transfer using the functions + BSP_SRAM_ReadData_DMA()/BSP_SRAM_WriteData_DMA(). + o The AHB access is performed with 16-bit width transaction, the DMA transfer + configuration is fixed at single (no burst) halfword transfer + (see the SRAM_MspInit() static function). + o User can implement his own functions for read/write access with his desired + configurations. + o If interrupt mode is used for DMA transfer, the function BSP_SRAM_DMA_IRQHandler() + is called in IRQ handler file, to serve the generated interrupt once the DMA + transfer is complete. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_sram.c +- stm32f7xx_ll_fmc.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval_sram.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @defgroup STM32756G_EVAL_SRAM STM32756G_EVAL SRAM + * @{ + */ + +/** @defgroup STM32756G_EVAL_SRAM_Private_Types_Definitions SRAM Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SRAM_Private_Defines SRAM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SRAM_Private_Macros SRAM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SRAM_Private_Variables SRAM Private Variables + * @{ + */ +SRAM_HandleTypeDef sramHandle; +static FMC_NORSRAM_TimingTypeDef Timing; +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SRAM_Private_Functions_Prototypes SRAM Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SRAM_Private_Functions SRAM Private Functions + * @{ + */ + +/** + * @brief Initializes the SRAM device. + * @retval SRAM status + */ +uint8_t BSP_SRAM_Init(void) +{ + static uint8_t sram_status = SRAM_ERROR; + /* SRAM device configuration */ + sramHandle.Instance = FMC_NORSRAM_DEVICE; + sramHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + /* SRAM device configuration */ + /* Timing configuration derived from system clock (up to 216Mhz) + for 108Mhz as SRAM clock frequency */ + Timing.AddressSetupTime = 2; + Timing.AddressHoldTime = 1; + Timing.DataSetupTime = 2; + Timing.BusTurnAroundDuration = 1; + Timing.CLKDivision = 2; + Timing.DataLatency = 2; + Timing.AccessMode = FMC_ACCESS_MODE_A; + + sramHandle.Init.NSBank = FMC_NORSRAM_BANK3; + sramHandle.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; + sramHandle.Init.MemoryType = FMC_MEMORY_TYPE_SRAM; + sramHandle.Init.MemoryDataWidth = SRAM_MEMORY_WIDTH; + sramHandle.Init.BurstAccessMode = SRAM_BURSTACCESS; + sramHandle.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; + sramHandle.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; + sramHandle.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; + sramHandle.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE; + sramHandle.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; + sramHandle.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE; + sramHandle.Init.WriteBurst = SRAM_WRITEBURST; + sramHandle.Init.ContinuousClock = CONTINUOUSCLOCK_FEATURE; + + /* SRAM controller initialization */ + BSP_SRAM_MspInit(&sramHandle, NULL); /* __weak function can be rewritten by the application */ + if(HAL_SRAM_Init(&sramHandle, &Timing, &Timing) != HAL_OK) + { + sram_status = SRAM_ERROR; + } + else + { + sram_status = SRAM_OK; + } + return sram_status; +} + +/** + * @brief DeInitializes the SRAM device. + * @retval SRAM status + */ +uint8_t BSP_SRAM_DeInit(void) +{ + static uint8_t sram_status = SRAM_ERROR; + /* SRAM device de-initialization */ + sramHandle.Instance = FMC_NORSRAM_DEVICE; + sramHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + if(HAL_SRAM_DeInit(&sramHandle) != HAL_OK) + { + sram_status = SRAM_ERROR; + } + else + { + sram_status = SRAM_OK; + } + + /* SRAM controller de-initialization */ + BSP_SRAM_MspDeInit(&sramHandle, NULL); + + return sram_status; +} + +/** + * @brief Reads an amount of data from the SRAM device in polling mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SRAM status + */ +uint8_t BSP_SRAM_ReadData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Read_16b(&sramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SRAM_ERROR; + } + else + { + return SRAM_OK; + } +} + +/** + * @brief Reads an amount of data from the SRAM device in DMA mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SRAM status + */ +uint8_t BSP_SRAM_ReadData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Read_DMA(&sramHandle, (uint32_t *)uwStartAddress, (uint32_t *)pData, uwDataSize) != HAL_OK) + { + return SRAM_ERROR; + } + else + { + return SRAM_OK; + } +} + +/** + * @brief Writes an amount of data from the SRAM device in polling mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SRAM status + */ +uint8_t BSP_SRAM_WriteData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Write_16b(&sramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SRAM_ERROR; + } + else + { + return SRAM_OK; + } +} + +/** + * @brief Writes an amount of data from the SRAM device in DMA mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SRAM status + */ +uint8_t BSP_SRAM_WriteData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Write_DMA(&sramHandle, (uint32_t *)uwStartAddress, (uint32_t *)pData, uwDataSize) != HAL_OK) + { + return SRAM_ERROR; + } + else + { + return SRAM_OK; + } +} + +/** + * @brief Initializes SRAM MSP. + * @param hsram: SRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SRAM_MspInit(SRAM_HandleTypeDef *hsram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable FMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + + /* Enable chosen DMAx clock */ + __SRAM_DMAx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF12_FMC; + + /* GPIOD configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_8 |\ + GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 |\ + GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOE configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3| GPIO_PIN_4 | GPIO_PIN_7 |\ + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |\ + GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOF configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOF, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_10; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + /* Configure common DMA parameters */ + dma_handle.Init.Channel = SRAM_DMAx_CHANNEL; + dma_handle.Init.Direction = DMA_MEMORY_TO_MEMORY; + dma_handle.Init.PeriphInc = DMA_PINC_ENABLE; + dma_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + dma_handle.Init.Mode = DMA_NORMAL; + dma_handle.Init.Priority = DMA_PRIORITY_HIGH; + dma_handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + dma_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_handle.Init.MemBurst = DMA_MBURST_SINGLE; + dma_handle.Init.PeriphBurst = DMA_PBURST_SINGLE; + + dma_handle.Instance = SRAM_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsram, hdma, dma_handle); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&dma_handle); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&dma_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SRAM_DMAx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SRAM_DMAx_IRQn); +} + + +/** + * @brief DeInitializes SRAM MSP. + * @param hsram: SRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SRAM_MspDeInit(SRAM_HandleTypeDef *hsram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + + /* Disable NVIC configuration for DMA interrupt */ + HAL_NVIC_DisableIRQ(SRAM_DMAx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_handle.Instance = SRAM_DMAx_STREAM; + HAL_DMA_DeInit(&dma_handle); + + /* GPIO pins clock, FMC clock and DMA clock can be shut down in the applications + by surcharging this __weak function */ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sram.h b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sram.h new file mode 100644 index 00000000..ce87a11d --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_sram.h @@ -0,0 +1,148 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_sram.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32756g_eval_sram.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32756G_EVAL_SRAM_H +#define __STM32756G_EVAL_SRAM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @addtogroup STM32756G_EVAL_SRAM + * @{ + */ + +/** @defgroup STM32756G_EVAL_SRAM_Exported_Types SRAM Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SRAM_Exported_Constants SRAM Exported Constants + * @{ + */ + +/** + * @brief SRAM status structure definition + */ +#define SRAM_OK ((uint8_t)0x00) +#define SRAM_ERROR ((uint8_t)0x01) + +#define SRAM_DEVICE_ADDR ((uint32_t)0x68000000) +#define SRAM_DEVICE_SIZE ((uint32_t)0x200000) /* SRAM device size in MBytes */ + +/* #define SRAM_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_8*/ +#define SRAM_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_16 + +#define SRAM_BURSTACCESS FMC_BURST_ACCESS_MODE_DISABLE +/* #define SRAM_BURSTACCESS FMC_BURST_ACCESS_MODE_ENABLE*/ + +#define SRAM_WRITEBURST FMC_WRITE_BURST_DISABLE +/* #define SRAM_WRITEBURST FMC_WRITE_BURST_ENABLE */ + +#define CONTINUOUSCLOCK_FEATURE FMC_CONTINUOUS_CLOCK_SYNC_ONLY +/* #define CONTINUOUSCLOCK_FEATURE FMC_CONTINUOUS_CLOCK_SYNC_ASYNC */ + +/* DMA definitions for SRAM DMA transfer */ +#define __SRAM_DMAx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define __SRAM_DMAx_CLK_DISABLE __HAL_RCC_DMA2_CLK_DISABLE +#define SRAM_DMAx_CHANNEL DMA_CHANNEL_0 +#define SRAM_DMAx_STREAM DMA2_Stream4 +#define SRAM_DMAx_IRQn DMA2_Stream4_IRQn +#define BSP_SRAM_DMA_IRQHandler DMA2_Stream4_IRQHandler +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SRAM_Exported_Macro SRAM Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_SRAM_Exported_Functions SRAM Exported Functions + * @{ + */ +uint8_t BSP_SRAM_Init(void); +uint8_t BSP_SRAM_DeInit(void); +uint8_t BSP_SRAM_ReadData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_SRAM_ReadData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_SRAM_WriteData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_SRAM_WriteData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_SRAM_MspInit(SRAM_HandleTypeDef *hsram, void *Params); +void BSP_SRAM_MspDeInit(SRAM_HandleTypeDef *hsram, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32756G_EVAL_SRAM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_ts.c b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_ts.c new file mode 100644 index 00000000..53f6df30 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_ts.c @@ -0,0 +1,305 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_ts.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the Touch + * Screen on STM32756G-EVAL and STM32746G-EVAL evaluation boards. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the touch screen module of the STM32756G-EVAL + evaluation board on the AMPIRE 640x480 LCD mounted on MB1063 or AMPIRE + 480x272 LCD mounted on MB1046 daughter board. + - If the AMPIRE 640x480 LCD is used, the TS3510 or EXC7200 component driver + must be included according to the touch screen driver present on this board. + - If the AMPIRE 480x272 LCD is used, the STMPE811 IO expander device component + driver must be included in order to run the TS module commanded by the IO + expander device, the MFXSTM32L152 IO expander device component driver must be + also included in case of interrupt mode use of the TS. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the TS module using the BSP_TS_Init() function. This + function includes the MSP layer hardware resources initialization and the + communication layer configuration to start the TS use. The LCD size properties + (x and y) are passed as parameters. + o If TS interrupt mode is desired, you must configure the TS interrupt mode + by calling the function BSP_TS_ITConfig(). The TS interrupt mode is generated + as an external interrupt whenever a touch is detected. + The interrupt mode internally uses the IO functionalities driver driven by + the IO expander, to configure the IT line. + + + Touch screen use + o The touch screen state is captured whenever the function BSP_TS_GetState() is + used. This function returns information about the last LCD touch occurred + in the TS_StateTypeDef structure. + o If TS interrupt mode is used, the function BSP_TS_ITGetStatus() is needed to get + the interrupt status. To clear the IT pending bits, you should call the + function BSP_TS_ITClear(). + o The IT is handled using the corresponding external interrupt IRQ handler, + the user IT callback treatment is implemented on the same external interrupt + callback. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32756g_eval_lcd.c +- exc7200.c +- ts3510.c +- stmpe811.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval_ts.h" +#include "stm32756g_eval_io.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @defgroup STM32756G_EVAL_TS STM32756G_EVAL TS + * @{ + */ + +/** @defgroup STM32756G_EVAL_TS_Private_Types_Definitions TS Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_TS_Private_Defines TS Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_TS_Private_Macros TS Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_TS_Private_Variables TS Private Variables + * @{ + */ +static TS_DrvTypeDef *tsDriver; +static uint16_t tsXBoundary, tsYBoundary; +static uint8_t tsOrientation; +static uint8_t I2cAddress; +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_TS_Private_Functions_Prototypes TS Private Functions Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_TS_Private_Functions TS Private Functions + * @{ + */ + +/** + * @brief Initializes and configures the touch screen functionalities and + * configures all necessary hardware resources (GPIOs, clocks..). + * @param xSize: Maximum X size of the TS area on LCD + * @param ySize: Maximum Y size of the TS area on LCD + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_Init(uint16_t xSize, uint16_t ySize) +{ + uint8_t status = TS_OK; + tsXBoundary = xSize; + tsYBoundary = ySize; + + /* Read ID and verify if the IO expander is ready */ + if(stmpe811_ts_drv.ReadID(TS_I2C_ADDRESS) == STMPE811_ID) + { + /* Initialize the TS driver structure */ + tsDriver = &stmpe811_ts_drv; + I2cAddress = TS_I2C_ADDRESS; + tsOrientation = TS_SWAP_Y; + } + else + { + IOE_Init(); + + /* Check TS3510 touch screen driver presence to determine if TS3510 or + * EXC7200 driver will be used */ + if(BSP_TS3510_IsDetected() == 0) + { + /* Initialize the TS driver structure */ + tsDriver = &ts3510_ts_drv; + I2cAddress = TS3510_I2C_ADDRESS; + } + else + { + /* Initialize the TS driver structure */ + tsDriver = &exc7200_ts_drv; + I2cAddress = EXC7200_I2C_ADDRESS; + } + tsOrientation = TS_SWAP_NONE; + } + + /* Initialize the TS driver */ + tsDriver->Init(I2cAddress); + tsDriver->Start(I2cAddress); + + return status; +} + +/** + * @brief DeInitializes the TouchScreen. + * @retval TS state + */ +uint8_t BSP_TS_DeInit(void) +{ + /* Actually ts_driver does not provide a DeInit function */ + return TS_OK; +} + +/** + * @brief Configures and enables the touch screen interrupts. + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_ITConfig(void) +{ + /* Initialize the IO */ + BSP_IO_Init(); + + /* Configure TS IT line IO */ + BSP_IO_ConfigPin(TS_INT_PIN, IO_MODE_IT_FALLING_EDGE); + + /* Enable the TS ITs */ + tsDriver->EnableIT(I2cAddress); + + return TS_OK; +} + +/** + * @brief Gets the touch screen interrupt status. + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_ITGetStatus(void) +{ + /* Return the TS IT status */ + return (tsDriver->GetITStatus(I2cAddress)); +} + +/** + * @brief Returns status and positions of the touch screen. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State) +{ + static uint32_t _x = 0, _y = 0; + uint16_t x_diff, y_diff , x , y; + uint16_t swap; + + TS_State->TouchDetected = tsDriver->DetectTouch(I2cAddress); + + if(TS_State->TouchDetected) + { + tsDriver->GetXY(I2cAddress, &x, &y); + + if(tsOrientation & TS_SWAP_X) + { + x = 4096 - x; + } + + if(tsOrientation & TS_SWAP_Y) + { + y = 4096 - y; + } + + if(tsOrientation & TS_SWAP_XY) + { + swap = y; + y = x; + x = swap; + } + + x_diff = x > _x? (x - _x): (_x - x); + y_diff = y > _y? (y - _y): (_y - y); + + if (x_diff + y_diff > 5) + { + _x = x; + _y = y; + } + + TS_State->x = (tsXBoundary * _x) >> 12; + TS_State->y = (tsYBoundary * _y) >> 12; + } + return TS_OK; +} + +/** + * @brief Clears all touch screen interrupts. + * @retval None + */ +void BSP_TS_ITClear(void) +{ + /* Clear all IO IT pin */ + BSP_IO_ITClear(); + + /* Clear TS IT pending bits */ + tsDriver->ClearIT(I2cAddress); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_ts.h b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_ts.h new file mode 100644 index 00000000..c27112f9 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32756G_EVAL/stm32756g_eval_ts.h @@ -0,0 +1,140 @@ +/** + ****************************************************************************** + * @file stm32756g_eval_ts.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32756g_eval_ts.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32756G_EVAL_TS_H +#define __STM32756G_EVAL_TS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32756g_eval.h" +/* Include IOExpander(STMPE811) component Driver */ +#include "../Components/stmpe811/stmpe811.h" +/* Include TouchScreen component drivers */ +#include "../Components/ts3510/ts3510.h" +#include "../Components/exc7200/exc7200.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32756G_EVAL + * @{ + */ + +/** @addtogroup STM32756G_EVAL_TS + * @{ + */ + +/** @defgroup STM32756G_EVAL_TS_Exported_Types TS Exported Types + * @{ + */ +typedef struct +{ + uint16_t TouchDetected; + uint16_t x; + uint16_t y; + uint16_t z; +}TS_StateTypeDef; +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_TS_Exported_Constants TS Exported Constants + * @{ + */ +#define TS_SWAP_NONE ((uint8_t)0x00) +#define TS_SWAP_X ((uint8_t)0x01) +#define TS_SWAP_Y ((uint8_t)0x02) +#define TS_SWAP_XY ((uint8_t)0x04) + +typedef enum +{ + TS_OK = 0x00, + TS_ERROR = 0x01, + TS_TIMEOUT = 0x02 +}TS_StatusTypeDef; + +/* Interrupt sources pins definition */ +#define TS_INT_PIN LCD_INT_PIN +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_TS_Exported_Macros TS Exported Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32756G_EVAL_TS_Exported_Functions TS Exported Functions + * @{ + */ +uint8_t BSP_TS_Init(uint16_t xSize, uint16_t ySize); +uint8_t BSP_TS_DeInit(void); +uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State); +uint8_t BSP_TS_ITConfig(void); +uint8_t BSP_TS_ITGetStatus(void); +void BSP_TS_ITClear(void); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32756G_EVAL_TS_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/Release_Notes.html new file mode 100644 index 00000000..9826b8da --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/Release_Notes.html @@ -0,0 +1,358 @@ + + + + + + + + + + + + + + + Release Notes for STM32F723E-Discovery Kit BSP Drivers + + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for STM32F723E-Discovery Board Drivers

+

Copyright +2016 STMicroelectronics

+

+
+

 

+ + + + + + +

The BSP (Board Specific +Package) drivers are parts of the STM32Cube package based on the HAL +drivers and provide a set of high level APIs relative to the hardware +components and features in the evaluation boards, discovery kits and nucleo +boards coming with the STM32Cube package for a given STM32 serie.

+

The BSP drivers allow a quick access to the boards’ +services using high level APIs and without any specific configuration as the +link with the HAL and the external components is done in intrinsic within the drivers.
+

+

From project settings points of view, user has only +to add the necessary driver’s files in the workspace and call the needed +functions from examples. However some low level +configuration functions are weak and can be overridden by the applications if user +wants to change some BSP drivers default behavior.

+ + +

    Update History

V1.0.2 / 24-August-2017

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • stm32f723e_discovery_lcd.c:
    • Fix compilation errors with SW4STM32 toolchain.
  • stm32f723e_discovery.c:
    • Upgrade version to v1.0.2

V1.0.1 / 25-May-2017

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • Add general description of BSP drivers
    +
  • Add Dependencies section
    +
  • Support of PDSC

V1.0.0 / 30-December-2016

+ +

Main +Changes

+
    +
  • First official Release for STM32F723E-Discovery +board drivers.

Dependencies

+ + + + + + +
  • STM32F7xx_HAL_Driver V1.2.0
    +
  • BSP Common V4.0.1

License

+
+
Redistribution and use in +source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
    +
  1. Redistributions of source +code must retain the above copyright notice, this list of conditions +and the following disclaimer.
  2. +
  3. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution.
  4. +
  5. Neither the name of +STMicroelectronics nor the names of its contributors may be used to +endorse or promote products derived
    +
  6. +
+        +from this software without specific prior written permission.
+
+ THIS +SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE.
+
+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery.c b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery.c new file mode 100644 index 00000000..d35c1a55 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery.c @@ -0,0 +1,1053 @@ +/** + ****************************************************************************** + * @file stm32f723e_discovery.c + * @author MCD Application Team + * @brief This file provides a set of firmware functions to manage LEDs, + * push-buttons, external PSRAM, external QSPI Flash, TS available on + * STM32F723E-Discovery board (MB1260) from STMicroelectronics. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_uart.c +- stm32f7xx_hal_i2c.c +- stm32f7xx_hal_sram.c +- stm32f7xx_hal_rcc_ex.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f723e_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_LOW_LEVEL STM32F723E-DISCOVERY LOW LEVEL + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_LOW_LEVEL_Private_TypesDefinitions STM32F723E Discovery Low Level Private Typedef + * @{ + */ +typedef struct +{ + __IO uint16_t REG; + __IO uint16_t RAM; +}LCD_CONTROLLER_TypeDef; +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LOW_LEVEL_Private_Defines LOW_LEVEL Private Defines + * @{ + */ +/** + * @brief STM32F723E Discovery BSP Driver version number V1.0.2 + */ +#define __STM32F723E_DISCOVERY_BSP_VERSION_MAIN (0x01) /*!< [31:24] main version */ +#define __STM32F723E_DISCOVERY_BSP_VERSION_SUB1 (0x00) /*!< [23:16] sub1 version */ +#define __STM32F723E_DISCOVERY_BSP_VERSION_SUB2 (0x02) /*!< [15:8] sub2 version */ +#define __STM32F723E_DISCOVERY_BSP_VERSION_RC (0x00) /*!< [7:0] release candidate */ +#define __STM32F723E_DISCOVERY_BSP_VERSION ((__STM32F723E_DISCOVERY_BSP_VERSION_MAIN << 24)\ + |(__STM32F723E_DISCOVERY_BSP_VERSION_SUB1 << 16)\ + |(__STM32F723E_DISCOVERY_BSP_VERSION_SUB2 << 8 )\ + |(__STM32F723E_DISCOVERY_BSP_VERSION_RC)) + +/* We use BANK2 as we use FMC_NE2 signal */ +#define FMC_BANK2_BASE ((uint32_t)(0x60000000 | 0x04000000)) +#define FMC_BANK2 ((LCD_CONTROLLER_TypeDef *) FMC_BANK2_BASE) +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LOW_LEVEL_Private_Macros LOW_LEVEL Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LOW_LEVEL_Private_Variables LOW_LEVEL Private Variables + * @{ + */ +uint32_t GPIO_PIN[LEDn] = {LED5_PIN, + LED6_PIN}; + +GPIO_TypeDef* GPIO_PORT[LEDn] = {LED5_GPIO_PORT, + LED6_GPIO_PORT}; + +GPIO_TypeDef* BUTTON_PORT[BUTTONn] = {WAKEUP_BUTTON_GPIO_PORT }; + +const uint16_t BUTTON_PIN[BUTTONn] = {WAKEUP_BUTTON_PIN }; + +const uint16_t BUTTON_IRQn[BUTTONn] = {WAKEUP_BUTTON_EXTI_IRQn }; + +USART_TypeDef* COM_USART[COMn] = {DISCOVERY_COM1}; + +GPIO_TypeDef* COM_TX_PORT[COMn] = {DISCOVERY_COM1_TX_GPIO_PORT}; + +GPIO_TypeDef* COM_RX_PORT[COMn] = {DISCOVERY_COM1_RX_GPIO_PORT}; + +const uint16_t COM_TX_PIN[COMn] = {DISCOVERY_COM1_TX_PIN}; + +const uint16_t COM_RX_PIN[COMn] = {DISCOVERY_COM1_RX_PIN}; + +const uint16_t COM_TX_AF[COMn] = {DISCOVERY_COM1_TX_AF}; + +const uint16_t COM_RX_AF[COMn] = {DISCOVERY_COM1_RX_AF}; + +static I2C_HandleTypeDef hI2cAudioHandler = {0}; +static I2C_HandleTypeDef hI2cTsHandler = {0}; + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LOW_LEVEL_Private_FunctionPrototypes LOW_LEVEL Private FunctionPrototypes + * @{ + */ +static void I2Cx_MspInit(I2C_HandleTypeDef *i2c_handler); +static void I2Cx_Init(I2C_HandleTypeDef *i2c_handler); + +static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static void I2Cx_Error(I2C_HandleTypeDef *i2c_handler, uint8_t Addr); + +static void FMC_BANK2_WriteData(uint16_t Data); +static void FMC_BANK2_WriteReg(uint8_t Reg); +static uint16_t FMC_BANK2_ReadData(void); +static void FMC_BANK2_Init(void); +static void FMC_BANK2_MspInit(void); + +/* LCD IO functions */ +void LCD_IO_Init(void); +void LCD_IO_WriteData(uint16_t RegValue); +void LCD_IO_WriteReg(uint8_t Reg); +void LCD_IO_WriteMultipleData(uint16_t *pData, uint32_t Size); +uint16_t LCD_IO_ReadData(void); +void LCD_IO_Delay(uint32_t Delay); + +/* AUDIO IO functions */ +void AUDIO_IO_Init(void); +void AUDIO_IO_DeInit(void); +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value); +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg); +void AUDIO_IO_Delay(uint32_t Delay); + +/* TouchScreen (TS) IO functions */ +void TS_IO_Init(void); +void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg); +uint16_t TS_IO_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); +void TS_IO_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); +void TS_IO_Delay(uint32_t Delay); + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_BSP_Public_Functions BSP Public Functions + * @{ + */ + + /** + * @brief This method returns the STM32F723E Discovery BSP Driver revision + * @retval version: 0xXYZR (8bits for each decimal, R for RC) + */ +uint32_t BSP_GetVersion(void) +{ + return __STM32F723E_DISCOVERY_BSP_VERSION; +} + +/** + * @brief Configures LED GPIO. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED5 + * @arg LED6 + * @retval None + */ +void BSP_LED_Init(Led_TypeDef Led) +{ + GPIO_InitTypeDef gpio_init_structure; + + LEDx_GPIO_CLK_ENABLE(Led); + /* Configure the GPIO_LED pin */ + gpio_init_structure.Pin = GPIO_PIN[Led]; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + + HAL_GPIO_Init(GPIO_PORT[Led], &gpio_init_structure); + +} + + +/** + * @brief DeInit LEDs. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED5 + * @arg LED6 + * @note Led DeInit does not disable the GPIO clock + * @retval None + */ +void BSP_LED_DeInit(Led_TypeDef Led) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* DeInit the GPIO_LED pin */ + gpio_init_structure.Pin = GPIO_PIN[Led]; + + /* Turn off LED */ + HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_RESET); + HAL_GPIO_DeInit(GPIO_PORT[Led], gpio_init_structure.Pin); +} + +/** + * @brief Turns selected LED On. + * @param Led: LED to be set on + * This parameter can be one of the following values: + * @arg LED5 + * @arg LED6 + * @retval None + */ +void BSP_LED_On(Led_TypeDef Led) +{ + HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_SET); +} + +/** + * @brief Turns selected LED Off. + * @param Led: LED to be set off + * This parameter can be one of the following values: + * @arg LED5 + * @arg LED6 + * @retval None + */ +void BSP_LED_Off(Led_TypeDef Led) +{ + HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_RESET); +} + +/** + * @brief Toggles the selected LED. + * @param Led: LED to be toggled + * This parameter can be one of the following values: + * @arg LED5 + * @arg LED6 + * @retval None + */ +void BSP_LED_Toggle(Led_TypeDef Led) +{ + HAL_GPIO_TogglePin(GPIO_PORT[Led], GPIO_PIN[Led]); +} + +/** + * @brief Configures button GPIO and EXTI Line. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_USER: User Push Button + * @param Button_Mode: Button mode + * This parameter can be one of the following values: + * @arg BUTTON_MODE_GPIO: Button will be used as simple IO + * @arg BUTTON_MODE_EXTI: Button will be connected to EXTI line + * with interrupt generation capability + * @retval None + */ +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable the BUTTON clock */ + BUTTON_GPIO_CLK_ENABLE(); + + if(Button_Mode == BUTTON_MODE_GPIO) + { + /* Configure Button pin as input */ + gpio_init_structure.Pin = BUTTON_PIN[Button]; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure); + } + + if(Button_Mode == BUTTON_MODE_EXTI) + { + /* Configure Button pin as input with External interrupt */ + gpio_init_structure.Pin = BUTTON_PIN[Button]; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + + gpio_init_structure.Mode = GPIO_MODE_IT_RISING; + + HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure); + + /* Enable and set Button EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(BUTTON_IRQn[Button]), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + } +} + +/** + * @brief Push Button DeInit. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_USER: User Push Button + * @note PB DeInit does not disable the GPIO clock + * @retval None + */ +void BSP_PB_DeInit(Button_TypeDef Button) +{ + GPIO_InitTypeDef gpio_init_structure; + + gpio_init_structure.Pin = BUTTON_PIN[Button]; + HAL_NVIC_DisableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + HAL_GPIO_DeInit(BUTTON_PORT[Button], gpio_init_structure.Pin); +} + + +/** + * @brief Returns the selected button state. + * @param Button: Button to be checked + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_USER: User Push Button + * @retval The Button GPIO pin value + */ +uint32_t BSP_PB_GetState(Button_TypeDef Button) +{ + return HAL_GPIO_ReadPin(BUTTON_PORT[Button], BUTTON_PIN[Button]); +} + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LOW_LEVEL_Private_Functions STM32F723E_DISCOVERY_LOW_LEVEL Private Functions + * @{ + */ +/** + * @brief Configures COM port. + * @param COM: COM port to be configured. + * This parameter can be one of the following values: + * @arg COM1 + * @param huart: Pointer to a UART_HandleTypeDef structure that contains the + * configuration information for the specified USART peripheral. + * @retval None + */ +void BSP_COM_Init(COM_TypeDef COM, UART_HandleTypeDef *huart) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable GPIO clock */ + DISCOVERY_COMx_TX_GPIO_CLK_ENABLE(COM); + DISCOVERY_COMx_RX_GPIO_CLK_ENABLE(COM); + + /* Enable USART clock */ + DISCOVERY_COMx_CLK_ENABLE(COM); + + /* Configure USART Tx as alternate function */ + gpio_init_structure.Pin = COM_TX_PIN[COM]; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Alternate = COM_TX_AF[COM]; + HAL_GPIO_Init(COM_TX_PORT[COM], &gpio_init_structure); + + /* Configure USART Rx as alternate function */ + gpio_init_structure.Pin = COM_RX_PIN[COM]; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = COM_RX_AF[COM]; + HAL_GPIO_Init(COM_RX_PORT[COM], &gpio_init_structure); + + /* USART configuration */ + huart->Instance = COM_USART[COM]; + HAL_UART_Init(huart); +} + +/** + * @brief DeInit COM port. + * @param COM: COM port to be configured. + * This parameter can be one of the following values: + * @arg COM1 + * @arg COM2 + * @param huart: Pointer to a UART_HandleTypeDef structure that contains the + * configuration information for the specified USART peripheral. + * @retval None + */ +void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart) +{ + /* USART configuration */ + huart->Instance = COM_USART[COM]; + HAL_UART_DeInit(huart); + + /* Enable USART clock */ + DISCOVERY_COMx_CLK_DISABLE(COM); + + /* DeInit GPIO pins can be done in the application + (by surcharging this __weak function) */ + + /* GPIO pins clock, FMC clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/******************************************************************************* + BUS OPERATIONS +*******************************************************************************/ + +/******************************* I2C Routines *********************************/ +/** + * @brief Initializes I2C MSP. + * @param i2c_handler : I2C handler + * @retval None + */ +static void I2Cx_MspInit(I2C_HandleTypeDef *i2c_handler) +{ + GPIO_InitTypeDef gpio_init_structure; + + if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cAudioHandler)) + { + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + DISCOVERY_AUDIO_I2Cx_SCL_GPIO_CLK_ENABLE(); + DISCOVERY_AUDIO_I2Cx_SDA_GPIO_CLK_ENABLE(); + /* Configure I2C Tx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_AUDIO_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = DISCOVERY_AUDIO_I2Cx_SCL_AF; + HAL_GPIO_Init(DISCOVERY_AUDIO_I2Cx_SCL_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C Rx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_AUDIO_I2Cx_SDA_PIN; + gpio_init_structure.Alternate = DISCOVERY_AUDIO_I2Cx_SDA_AF; + HAL_GPIO_Init(DISCOVERY_AUDIO_I2Cx_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + DISCOVERY_AUDIO_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + DISCOVERY_AUDIO_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + DISCOVERY_AUDIO_I2Cx_RELEASE_RESET(); + + /* Enable and set I2C1 Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_AUDIO_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_AUDIO_I2Cx_EV_IRQn); + + /* Enable and set I2C1 Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_AUDIO_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_AUDIO_I2Cx_ER_IRQn); + + } + else if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cTsHandler)) + { + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + TS_I2Cx_SCL_GPIO_CLK_ENABLE(); + TS_I2Cx_SDA_GPIO_CLK_ENABLE(); + /* Configure I2C SCL as alternate function */ + gpio_init_structure.Pin = TS_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; + gpio_init_structure.Alternate = TS_I2Cx_SCL_AF; + HAL_GPIO_Init(TS_I2Cx_SCL_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C SDA as alternate function */ + gpio_init_structure.Pin = TS_I2Cx_SDA_PIN; + gpio_init_structure.Alternate = TS_I2Cx_SDA_AF; + HAL_GPIO_Init(TS_I2Cx_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + TS_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + TS_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + TS_I2Cx_RELEASE_RESET(); + + /* Enable and set I2C Interrupt to a lower priority */ + HAL_NVIC_SetPriority(TS_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(TS_I2Cx_EV_IRQn); + + /* Enable and set I2C Interrupt to a lower priority */ + HAL_NVIC_SetPriority(TS_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(TS_I2Cx_ER_IRQn); + + } + else + { + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_CLK_ENABLE(); + + /* Configure I2C Tx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_EXT_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = DISCOVERY_EXT_I2Cx_SCL_SDA_AF; + HAL_GPIO_Init(DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C Rx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_EXT_I2Cx_SDA_PIN; + HAL_GPIO_Init(DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + DISCOVERY_EXT_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + DISCOVERY_EXT_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + DISCOVERY_EXT_I2Cx_RELEASE_RESET(); + + /* Enable and set I2C1 Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_EXT_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_EXT_I2Cx_EV_IRQn); + + /* Enable and set I2C1 Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_EXT_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_EXT_I2Cx_ER_IRQn); + } +} + +/** + * @brief Initializes I2C HAL. + * @param i2c_handler : I2C handler + * @retval None + */ +static void I2Cx_Init(I2C_HandleTypeDef *i2c_handler) +{ + if(HAL_I2C_GetState(i2c_handler) == HAL_I2C_STATE_RESET) + { + if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cAudioHandler)) + { + /* Audio and LCD I2C configuration */ + i2c_handler->Instance = DISCOVERY_AUDIO_I2Cx; + } + else if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cTsHandler)) + { + /* TouchScreen I2C configuration */ + i2c_handler->Instance = TS_I2Cx; + } + else + { + /* External, camera and Arduino connector I2C configuration */ + i2c_handler->Instance = DISCOVERY_EXT_I2Cx; + } + i2c_handler->Init.Timing = DISCOVERY_I2Cx_TIMING; + i2c_handler->Init.OwnAddress1 = 0; + i2c_handler->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + i2c_handler->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + i2c_handler->Init.OwnAddress2 = 0; + i2c_handler->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + i2c_handler->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + + /* Init the I2C */ + I2Cx_MspInit(i2c_handler); + HAL_I2C_Init(i2c_handler); + } +} + +/** + * @brief Reads multiple data. + * @param i2c_handler : I2C handler + * @param Addr: I2C address + * @param Reg: Reg address + * @param MemAddress: memory address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddress, uint8_t *Buffer, uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Read(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* I2C error occured */ + I2Cx_Error(i2c_handler, Addr); + } + return status; +} + + +/** + * @brief Writes a value in a register of the device through BUS in using DMA mode. + * @param i2c_handler : I2C handler + * @param Addr: Device address on BUS Bus. + * @param Reg: The target register address to write + * @param MemAddress: memory address + * @param Buffer: The target register value to be written + * @param Length: buffer size to be written + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddress, uint8_t *Buffer, uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Write(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* Re-Initiaize the I2C Bus */ + I2Cx_Error(i2c_handler, Addr); + } + return status; +} + + +/** + * @brief Manages error callback by re-initializing I2C. + * @param i2c_handler : I2C handler + * @param Addr: I2C Address + * @retval None + */ +static void I2Cx_Error(I2C_HandleTypeDef *i2c_handler, uint8_t Addr) +{ + /* De-initialize the I2C communication bus */ + HAL_I2C_DeInit(i2c_handler); + + /* Re-Initialize the I2C communication bus */ + I2Cx_Init(i2c_handler); +} + +/** + * @} + */ + +/******************************************************************************* + LINK OPERATIONS +*******************************************************************************/ +/*************************** FMC Routines *************************************/ +/** + * @brief Initializes FMC_BANK2 MSP. + * @retval None + */ +static void FMC_BANK2_MspInit(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable FMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + + /* Enable FSMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + __HAL_RCC_FMC_FORCE_RESET(); + __HAL_RCC_FMC_RELEASE_RESET(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = GPIO_AF12_FMC; + + /* GPIOD configuration */ + /* LCD_PSRAM_D2, LCD_PSRAM_D3, LCD_PSRAM_NOE, LCD_PSRAM_NWE, PSRAM_NE1, LCD_PSRAM_D13, + LCD_PSRAM_D14, LCD_PSRAM_D15, PSRAM_A16, PSRAM_A17, LCD_PSRAM_D0, LCD_PSRAM_D1 */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7 | GPIO_PIN_8 |\ + GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOE configuration */ + /* PSRAM_NBL0, PSRAM_NBL1, LCD_PSRAM_D4, LCD_PSRAM_D5, LCD_PSRAM_D6, LCD_PSRAM_D7, + LCD_PSRAM_D8, LCD_PSRAM_D9, LCD_PSRAM_D10, LCD_PSRAM_D11, LCD_PSRAM_D12 */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 |GPIO_PIN_10 |\ + GPIO_PIN_11 | GPIO_PIN_12 |GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOF configuration */ + /* PSRAM_A0, PSRAM_A1, PSRAM_A2, PSRAM_A3, PSRAM_A4, PSRAM_A5, + PSRAM_A6, PSRAM_A7, PSRAM_A8, PSRAM_A9 */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 |\ + GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOF, &gpio_init_structure); + + /* GPIOG configuration */ + /* PSRAM_A10, PSRAM_A11, PSRAM_A12, PSRAM_A13, PSRAM_A14, PSRAM_A15, LCD_NE */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 |\ + GPIO_PIN_9 ; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); +} + + +/** + * @brief Initializes LCD IO. + * @retval None + */ +static void FMC_BANK2_Init(void) +{ + SRAM_HandleTypeDef hsram; + FMC_NORSRAM_TimingTypeDef sram_timing; + + /* GPIO configuration for FMC signals (LCD) */ + FMC_BANK2_MspInit(); + + /* PSRAM device configuration */ + hsram.Instance = FMC_NORSRAM_DEVICE; + hsram.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + /* Set parameters for LCD access (FMC_NORSRAM_BANK2) */ + hsram.Init.NSBank = FMC_NORSRAM_BANK2; + hsram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; + hsram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM; + hsram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16; + hsram.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE; + hsram.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; + hsram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; + hsram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; + hsram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE; + hsram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; + hsram.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE; + hsram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE; + hsram.Init.WriteFifo = FMC_WRITE_FIFO_DISABLE; + hsram.Init.PageSize = FMC_PAGE_SIZE_NONE; + hsram.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY; + + /* PSRAM device configuration */ + /* Timing configuration derived from system clock (up to 216Mhz) + for 108Mhz as PSRAM clock frequency */ + sram_timing.AddressSetupTime = 9; + sram_timing.AddressHoldTime = 2; + sram_timing.DataSetupTime = 6; + sram_timing.BusTurnAroundDuration = 1; + sram_timing.CLKDivision = 2; + sram_timing.DataLatency = 2; + sram_timing.AccessMode = FMC_ACCESS_MODE_A; + + /* Initialize the FMC controller for LCD (FMC_NORSRAM_BANK2) */ + HAL_SRAM_Init(&hsram, &sram_timing, &sram_timing); +} + +/** + * @brief Writes register value. + * @param Data: Data to be written + * @retval None + */ +static void FMC_BANK2_WriteData(uint16_t Data) +{ + /* Write 16-bit Reg */ + FMC_BANK2->RAM = Data; + __DSB(); +} + +/** + * @brief Writes register address. + * @param Reg: Register to be written + * @retval None + */ +static void FMC_BANK2_WriteReg(uint8_t Reg) +{ + /* Write 16-bit Index, then write register */ + FMC_BANK2->REG = Reg; + __DSB(); +} + +/** + * @brief Reads register value. + * @retval Read value + */ +static uint16_t FMC_BANK2_ReadData(void) +{ + return FMC_BANK2->RAM; +} + +/******************************************************************************* + LINK OPERATIONS +*******************************************************************************/ + +/********************************* LINK LCD ***********************************/ + +/** + * @brief Initializes LCD low level. + * @retval None + */ +void LCD_IO_Init(void) +{ + FMC_BANK2_Init(); +} + +/** + * @brief Writes data on LCD data register. + * @param RegValue: Register value to be written + * @retval None + */ +void LCD_IO_WriteData(uint16_t RegValue) +{ + /* Write 16-bit Reg */ + FMC_BANK2_WriteData(RegValue); + __DSB(); +} + +/** + * @brief Writes several data on LCD data register. + * @param pData: pointer on data to be written + * @param Size: data amount in 16bits short unit + * @retval None + */ +void LCD_IO_WriteMultipleData(uint16_t *pData, uint32_t Size) +{ + uint32_t i; + + for (i = 0; i < Size; i++) + { + FMC_BANK2_WriteData(pData[i]); + __DSB(); + } +} + +/** + * @brief Writes register on LCD register. + * @param Reg: Register to be written + * @retval None + */ +void LCD_IO_WriteReg(uint8_t Reg) +{ + /* Write 16-bit Index, then Write Reg */ + FMC_BANK2_WriteReg(Reg); + __DSB(); +} + +/** + * @brief Reads data from LCD data register. + * @retval Read data. + */ +uint16_t LCD_IO_ReadData(void) +{ + return FMC_BANK2_ReadData(); +} + +/** + * @brief LCD delay + * @param Delay: Delay in ms + * @retval None + */ +void LCD_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/********************************* LINK AUDIO *********************************/ + +/** + * @brief Initializes Audio low level. + */ +void AUDIO_IO_Init(void) +{ + I2Cx_Init(&hI2cAudioHandler); +} + +/** + * @brief DeInitializes Audio low level. + */ +void AUDIO_IO_DeInit(void) +{ + +} + +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param Value: Data to be written + * @retval None + */ +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value) +{ + uint16_t tmp = Value; + + Value = ((uint16_t)(tmp >> 8) & 0x00FF); + + Value |= ((uint16_t)(tmp << 8)& 0xFF00); + + I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_16BIT,(uint8_t*)&Value, 2); +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @retval Data to be read + */ +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg) +{ + uint16_t read_value = 0, tmp = 0; + + I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&read_value, 2); + + tmp = ((uint16_t)(read_value >> 8) & 0x00FF); + + tmp |= ((uint16_t)(read_value << 8)& 0xFF00); + + read_value = tmp; + + return read_value; +} + +/** + * @brief AUDIO Codec delay + * @param Delay: Delay in ms + */ +void AUDIO_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/******************************** LINK TS (TouchScreen) ***********************/ + +/** + * @brief Initializes Touchscreen low level. + * @retval None + */ +void TS_IO_Init(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + TS_RESET_GPIO_CLK_ENABLE(); + + /* Configure Button pin as input */ + gpio_init_structure.Pin = TS_RESET_PIN; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(TS_RESET_GPIO_PORT, &gpio_init_structure); + HAL_GPIO_WritePin(TS_RESET_GPIO_PORT, TS_RESET_PIN, GPIO_PIN_SET); + I2Cx_Init(&hI2cTsHandler); +} + +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param Value: Data to be written + * @retval None + */ +void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_WriteMultiple(&hI2cTsHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT,(uint8_t*)&Value, 1); +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @retval Data to be read + */ +uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg) +{ + uint8_t read_value = 0; + + I2Cx_ReadMultiple(&hI2cTsHandler, Addr, Reg, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&read_value, 1); + + return read_value; +} + +/** + * @brief Reads multiple data with I2C communication + * channel from TouchScreen. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval Number of read data + */ +uint16_t TS_IO_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + return I2Cx_ReadMultiple(&hI2cTsHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief Writes multiple data with I2C communication + * channel from MCU to TouchScreen. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval None + */ +void TS_IO_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + I2Cx_WriteMultiple(&hI2cTsHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief Delay function used in TouchScreen low level driver. + * @param Delay: Delay in ms + * @retval None + */ +void TS_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery.h b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery.h new file mode 100644 index 00000000..e76a95ba --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery.h @@ -0,0 +1,411 @@ +/** + ****************************************************************************** + * @file stm32f723e_discovery.h + * @author MCD Application Team + * @brief This file contains definitions for STM32F723E-Discovery LEDs, + * push-buttons hardware resources. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F723E_DISCOVERY_H +#define __STM32F723E_DISCOVERY_H + +#ifdef __cplusplus + extern "C" { +#endif + + + /* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY_LOW_LEVEL + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_LOW_LEVEL_Exported_Types STM32F723E Discovery Low Level Exported Types + * @{ + */ + +/** + * @brief Define for STM32F723E_DISCOVERY board + */ +#if !defined (USE_STM32F723E_DISCO) + #define USE_STM32F723E_DISCO +#endif + +/** @brief Led_TypeDef + * STM32F723E_Discovery board leds definitions. + */ +typedef enum +{ + LED5 = 0, + LED_RED = LED5, + LED6 = 1, + LED_GREEN = LED6 +} Led_TypeDef; + +/** @brief Button_TypeDef + * STM32F723E_Discovery board Buttons definitions. + */ +typedef enum +{ + BUTTON_WAKEUP = 0, +} Button_TypeDef; + +#define BUTTON_USER BUTTON_WAKEUP + +/** @brief ButtonMode_TypeDef + * STM32F723E_Discovery board Buttons Modes definitions. + */ +typedef enum +{ + BUTTON_MODE_GPIO = 0, + BUTTON_MODE_EXTI = 1 + +} ButtonMode_TypeDef; + +typedef enum +{ + PB_SET = 0, + PB_RESET = !PB_SET +} ButtonValue_TypeDef; + +typedef enum +{ + COM1 = 0, +}COM_TypeDef; + +/** @brief DISCO_Status_TypeDef + * STM32F723E_DISCO board Status return possible values. + */ +typedef enum +{ + DISCO_OK = 0, + DISCO_ERROR = 1 + +} DISCO_Status_TypeDef; + +/** + * @} + */ + +/** @addtogroup STM32F723E_DISCOVERY_LOW_LEVEL_LED STM32F723E Discovery Low Level Led + * @{ + */ +/* Always four leds for all revisions of Discovery boards */ +#define LEDn ((uint8_t)2) + + +/* 2 Leds are connected to MCU directly on PA7 and PB1 */ +#define LED5_GPIO_PORT ((GPIO_TypeDef*)GPIOA) +#define LED6_GPIO_PORT ((GPIO_TypeDef*)GPIOB) + +#define LED5_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define LED6_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() + +#define LED5_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define LED6_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE() + + +#define LEDx_GPIO_CLK_ENABLE(__INDEX__) do{if((__INDEX__) == 0) LED5_GPIO_CLK_ENABLE(); else \ + if((__INDEX__) == 1) LED6_GPIO_CLK_ENABLE(); \ + }while(0) + +#define LEDx_GPIO_CLK_DISABLE(__INDEX__) do{if((__INDEX__) == 0) LED5_GPIO_CLK_DISABLE(); else \ + if((__INDEX__) == 1) LED6_GPIO_CLK_DISABLE(); \ + }while(0) + +#define LED5_PIN ((uint32_t)GPIO_PIN_7) +#define LED6_PIN ((uint32_t)GPIO_PIN_1) + +/** + * @} + */ + +/** @addtogroup STM32F723E_DISCOVERY_LOW_LEVEL_BUTTON STM32F723E Discovery Low Level Button + * @{ + */ +/* Only one User/Wakeup button */ +#define BUTTONn ((uint8_t)1) + +/** + * @brief Wakeup push-button + */ +#define WAKEUP_BUTTON_PIN GPIO_PIN_0 +#define WAKEUP_BUTTON_GPIO_PORT GPIOA +#define WAKEUP_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define WAKEUP_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define WAKEUP_BUTTON_EXTI_IRQn EXTI0_IRQn + +/* Define the USER button as an alias of the Wakeup button */ +#define USER_BUTTON_PIN WAKEUP_BUTTON_PIN +#define USER_BUTTON_GPIO_PORT WAKEUP_BUTTON_GPIO_PORT +#define USER_BUTTON_GPIO_CLK_ENABLE() WAKEUP_BUTTON_GPIO_CLK_ENABLE() +#define USER_BUTTON_GPIO_CLK_DISABLE() WAKEUP_BUTTON_GPIO_CLK_DISABLE() +#define USER_BUTTON_EXTI_IRQn WAKEUP_BUTTON_EXTI_IRQn + +#define BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LOW_LEVEL_Exported_Constants LOW_LEVEL Exported Constants + * @{ + */ +/** + * @brief USB OTG HS Over Current signal + */ +#define OTG_HS_OVER_CURRENT_PIN GPIO_PIN_10 +#define OTG_HS_OVER_CURRENT_PORT GPIOH +#define OTG_HS_OVER_CURRENT_PORT_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() + +/** + * @brief USB OTG FS Over Current signal + */ +#define OTG_FS_OVER_CURRENT_PIN GPIO_PIN_8 +#define OTG_FS_OVER_CURRENT_PORT GPIOC +#define OTG_FS_OVER_CURRENT_PORT_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() + +/** + * @brief TS_INT signal from TouchScreen + */ +#define TS_INT_PIN ((uint32_t)GPIO_PIN_9) +#define TS_INT_GPIO_PORT ((GPIO_TypeDef*)GPIOI) +#define TS_INT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define TS_INT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define TS_INT_EXTI_IRQn EXTI9_5_IRQn + +/** + * @brief TS RESET pin + */ +#define TS_RESET_PIN GPIO_PIN_9 +#define TS_RESET_GPIO_PORT GPIOH +#define TS_RESET_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() +#define TS_RESET_GPIO_CLK_DISABLE() __HAL_RCC_GPIOH_CLK_DISABLE() +#define TS_RESET_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief Definition for I2C3 Touchscreen Pins + * resources (touchescreen). + * Definition for I2C3 clock resources + */ +#define TS_I2Cx I2C3 +#define TS_I2Cx_CLK_ENABLE() __HAL_RCC_I2C3_CLK_ENABLE() +#define TS_I2Cx_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define TS_I2Cx_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() + +#define TS_I2Cx_FORCE_RESET() __HAL_RCC_I2C3_FORCE_RESET() +#define TS_I2Cx_RELEASE_RESET() __HAL_RCC_I2C3_RELEASE_RESET() + +/** @brief Definition for Touchscreen Pins + */ +#define TS_I2Cx_SCL_PIN GPIO_PIN_8 +#define TS_I2Cx_SCL_AF GPIO_AF4_I2C3 +#define TS_I2Cx_SCL_GPIO_PORT GPIOA +#define TS_I2Cx_SDA_PIN GPIO_PIN_8 +#define TS_I2Cx_SDA_AF GPIO_AF4_I2C3 +#define TS_I2Cx_SDA_GPIO_PORT GPIOH + +#define TS_I2Cx_EV_IRQn I2C3_EV_IRQn +#define TS_I2Cx_ER_IRQn I2C3_ER_IRQn + +/** + * @brief TouchScreen FT6206 Slave I2C address + */ +#define TS_I2C_ADDRESS ((uint16_t)0x70) + +/** + * @} + */ + +/** @addtogroup STM32F723E_DISCOVERY_LOW_LEVEL_COM STM32F723E DISCOVERY Low Level COM + * @{ + */ +#define COMn ((uint8_t)1) + +/** + * @brief Definition for COM port1, connected to USART2 + */ +#define DISCOVERY_COM1 USART2 +#define DISCOVERY_COM1_CLK_ENABLE() __HAL_RCC_USART2_CLK_ENABLE() +#define DISCOVERY_COM1_CLK_DISABLE() __HAL_RCC_USART2_CLK_DISABLE() + +#define DISCOVERY_COM1_TX_PIN GPIO_PIN_3 +#define DISCOVERY_COM1_TX_GPIO_PORT GPIOA +#define DISCOVERY_COM1_TX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define DISCOVERY_COM1_TX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define DISCOVERY_COM1_TX_AF GPIO_AF7_USART2 + +#define DISCOVERY_COM1_RX_PIN GPIO_PIN_2 +#define DISCOVERY_COM1_RX_GPIO_PORT GPIOA +#define DISCOVERY_COM1_RX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define DISCOVERY_COM1_RX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define DISCOVERY_COM1_RX_AF GPIO_AF7_USART2 + +#define DISCOVERY_COM1_IRQn USART2_IRQn + +#define DISCOVERY_COMx_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) {DISCOVERY_COM1_CLK_ENABLE();} } while(0) +#define DISCOVERY_COMx_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? DISCOVERY_COM1_CLK_DISABLE() : 0) + +#define DISCOVERY_COMx_TX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) {DISCOVERY_COM1_TX_GPIO_CLK_ENABLE();} } while(0) +#define DISCOVERY_COMx_TX_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? DISCOVERY_COM1_TX_GPIO_CLK_DISABLE() : 0) + +#define DISCOVERY_COMx_RX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) {DISCOVERY_COM1_RX_GPIO_CLK_ENABLE();} } while(0) +#define DISCOVERY_COMx_RX_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? DISCOVERY_COM1_RX_GPIO_CLK_DISABLE() : 0) + + +/** + * @brief Audio I2C Slave address + */ +#define AUDIO_I2C_ADDRESS ((uint16_t)0x34) + +/** + * @brief User can use this section to tailor I2C1 instance used and associated + * resources (audio codec). + * Definition for I2C1 clock resources + */ +#define DISCOVERY_AUDIO_I2Cx I2C1 +#define DISCOVERY_AUDIO_I2Cx_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE() +#define DISCOVERY_AUDIO_I2Cx_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define DISCOVERY_AUDIO_I2Cx_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() + +#define DISCOVERY_AUDIO_I2Cx_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET() +#define DISCOVERY_AUDIO_I2Cx_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET() + +/** @brief Definition for I2C1 Pins + */ +#define DISCOVERY_AUDIO_I2Cx_SCL_PIN GPIO_PIN_8 /*!< PB8 */ +#define DISCOVERY_AUDIO_I2Cx_SCL_AF GPIO_AF4_I2C1 +#define DISCOVERY_AUDIO_I2Cx_SCL_GPIO_PORT GPIOB +#define DISCOVERY_AUDIO_I2Cx_SDA_PIN GPIO_PIN_9 /*!< PB9 */ +#define DISCOVERY_AUDIO_I2Cx_SDA_AF GPIO_AF4_I2C1 +#define DISCOVERY_AUDIO_I2Cx_SDA_GPIO_PORT GPIOB +/** @brief Definition of I2C1 interrupt requests + */ +#define DISCOVERY_AUDIO_I2Cx_EV_IRQn I2C1_EV_IRQn +#define DISCOVERY_AUDIO_I2Cx_ER_IRQn I2C1_ER_IRQn + + +/* Definition for external, camera and Arduino connector I2Cx resources */ +#define DISCOVERY_EXT_I2Cx I2C2 +#define DISCOVERY_EXT_I2Cx_CLK_ENABLE() __HAL_RCC_I2C2_CLK_ENABLE() +#define DISCOVERY_EXT_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE() +#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() + +#define DISCOVERY_EXT_I2Cx_FORCE_RESET() __HAL_RCC_I2C2_FORCE_RESET() +#define DISCOVERY_EXT_I2Cx_RELEASE_RESET() __HAL_RCC_I2C2_RELEASE_RESET() + +/* Definition for I2Cx Pins */ +#define DISCOVERY_EXT_I2Cx_SCL_PIN GPIO_PIN_4 +#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT GPIOH +#define DISCOVERY_EXT_I2Cx_SCL_SDA_AF GPIO_AF4_I2C2 +#define DISCOVERY_EXT_I2Cx_SDA_PIN GPIO_PIN_5 + +/* I2C interrupt requests */ +#define DISCOVERY_EXT_I2Cx_EV_IRQn I2C2_EV_IRQn +#define DISCOVERY_EXT_I2Cx_ER_IRQn I2C2_ER_IRQn + + +/* I2C TIMING Register define when I2C clock source is SYSCLK */ +/* I2C TIMING is calculated from APB1 source clock = 50 MHz */ +/* Due to the big MOFSET capacity for adapting the camera level the rising time is very large (>1us) */ +/* 0x40912732 takes in account the big rising and aims a clock of 100khz */ +#ifndef DISCOVERY_I2Cx_TIMING +#define DISCOVERY_I2Cx_TIMING ((uint32_t)0x40912732) +#endif /* DISCOVERY_I2Cx_TIMING */ + + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LOW_LEVEL_Exported_Macros STM32F723E Discovery Low Level Exported Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LOW_LEVEL_Exported_Functions STM32F723E Discovery Low Level Exported Functions + * @{ + */ +uint32_t BSP_GetVersion(void); +void BSP_LED_Init(Led_TypeDef Led); +void BSP_LED_DeInit(Led_TypeDef Led); +void BSP_LED_On(Led_TypeDef Led); +void BSP_LED_Off(Led_TypeDef Led); +void BSP_LED_Toggle(Led_TypeDef Led); +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode); +void BSP_PB_DeInit(Button_TypeDef Button); +uint32_t BSP_PB_GetState(Button_TypeDef Button); +void BSP_COM_Init(COM_TypeDef COM, UART_HandleTypeDef *huart); +void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F723E_DISCOVERY_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_audio.c b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_audio.c new file mode 100644 index 00000000..5bb89bd8 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_audio.c @@ -0,0 +1,1446 @@ +/** + ****************************************************************************** + * @file stm32f723e_discovery_audio.c + * @author MCD Application Team + * @brief This file provides the Audio driver for the STM32F723E-DISCOVERY + * board. + @verbatim + How To use this driver: + ----------------------- + + This driver supports STM32F7xx devices on STM32F723E-DISCOVERY (MB1260) Evaluation boards. + + Call the function BSP_AUDIO_OUT_Init( + OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, + OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH) + Volume : Initial volume to be set (0 is min (mute), 100 is max (100%) + AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...) + this parameter is relative to the audio file/stream type. + ) + This function configures all the hardware required for the audio application (codec, I2C, SAI, + GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK. + If the returned value is different from AUDIO_OK or the function is stuck then the communication with + the codec has failed (try to un-plug the power or reset device in this case). + - OUTPUT_DEVICE_SPEAKER : only speaker will be set as output for the audio stream. + - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream. + - OUTPUT_DEVICE_BOTH : both Speaker and Headphone are used as outputs for the audio stream + at the same time. + + Call the function BSP_DISCOVERY_AUDIO_OUT_Play( + pBuffer: pointer to the audio data file address + Size : size of the buffer to be sent in Bytes + ) + to start playing (for the first time) from the audio file/stream. + + Call the function BSP_AUDIO_OUT_Pause() to pause playing + + Call the function BSP_AUDIO_OUT_Resume() to resume playing. + Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called + for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case). + Note. This function should be called only when the audio file is played or paused (not stopped). + + For each mode, you may need to implement the relative callback functions into your code. + The Callback functions are named AUDIO_OUT_XXX_CallBack() and only their prototypes are declared in + the stm32f723e_discovery_audio.h file. (refer to the example for more details on the callbacks implementations) + + To Stop playing, to modify the volume level, the frequency, the audio frame slot, + the device output mode the mute or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(), + AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetAudioFrameSlot(), BSP_AUDIO_OUT_SetOutputMode(), + BSP_AUDIO_OUT_SetMute() and BSP_AUDIO_OUT_Stop(). + + The driver API and the callback functions are at the end of the stm32f723e_discovery_audio.h file. + + + Call the function BSP_AUDIO_IN_Init( + InputDevice: physical input mode (INPUT_DEVICE_DIGITAL_MICROPHONE_1, + INPUT_DEVICE_DIGITAL_MICROPHONE_2, INPUT_DEVICE_DIGITAL_MIC1_MIC2 + or INPUT_DEVICE_INPUT_LINE_1) + Volume : Initial volume to be set (0 is min (mute), 100 is max (100%) + AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000...) + this parameter is relative to the audio file/stream type. + ) + This function configures all the hardware required for the AUDIO IN application (SAI blocks, + SAI clock source, GPIOs, DMA and interrupt if needed). + This function returns AUDIO_OK if configuration is OK.If the returned value is different from AUDIO_OK then + the configuration should be wrong. + Note: On STM32F723E-DISCOVERY, two SAI blocks are configured and their DMA streams are configured + in CIRCULAR mode. + + Call the function BSP_AUDIO_IN_RECORD( + pBuf: pointer to the recorded audio data file address + Size: size of the buffer to be written in Bytes + ) + to start recording from microphones. + + + Call the function BSP_AUDIO_IN_Pause() to pause recording + + Call the function BSP_AUDIO_IN_Resume() to recording playing. + Note. After calling BSP_AUDIO_IN_Pause() function for pause, only BSP_AUDIO_IN_Resume() should be called + for resume (it is not allowed to call BSP_AUDIO_IN_RECORD() in this case). + + Call the function BSP_AUDIO_IN_Stop() to stop recording + + For each mode, you may need to implement the relative callback functions into your code. + The Callback functions are named BSP_AUDIO_IN_XXX_CallBack() and only their prototypes are declared in + the stm32f723e_discovery_audio.h file. (refer to the example for more details on the callbacks implementations) + + + Call the function BSP_AUDIO_IN_OUT_Init( + InputDevice : physical input mode (INPUT_DEVICE_DIGITAL_MICROPHONE_1, + INPUT_DEVICE_DIGITAL_MICROPHONE_2, INPUT_DEVICE_DIGITAL_MIC1_MIC2 + or INPUT_DEVICE_INPUT_LINE_1) + OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, + OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH) + Volume : Initial volume to be set (0 is min (mute), 100 is max (100%) + AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...) + this parameter is relative to the audio file/stream type. + ) + This function configures all the hardware required for the AUDIO IN(record) and AUDIO OUT(play) + application (SAI blocks, SAI clock source, GPIOs, DMA and interrupt if needed). + + Driver architecture: + -------------------- + + This driver provides the High Audio Layer: consists of the function API exported in the stm32f723e_discovery_audio.h file + (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...) + + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/ + providing the audio file/stream. These functions are also included as local functions into + the stm32f723e_discovery_audio.c file (SAIx_Out_Init() and SAIx_Out_DeInit(), SAIx_In_Init() and SAIx_In_DeInit()) + + Known Limitations: + ------------------ + 1- If the TDM Format used to play in parallel 2 audio Stream (the first Stream is configured in codec SLOT0 and second + Stream in SLOT1) the Pause/Resume, volume and mute feature will control the both streams. + 2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, + File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file. + 3- Supports only Stereo audio streaming. + 4- Supports only 16-bits audio data size. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f723e_discovery.c +- stm32f7xx_hal_sai.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- wm8994.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f723e_discovery_audio.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO STM32F723E_DISCOVERY_AUDIO + * @brief This file includes the low layer driver for wm8994 Audio Codec + * available on STM32F723E-DISCOVERY discoveryuation board(MB1260). + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO_Private_Types STM32F723E_DISCOVERY_AUDIO Private Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO_Private_Defines STM32F723E_DISCOVERY_AUDIO Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO_Private_Macros STM32F723E_DISCOVERY_AUDIO Private Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO_Private_Variables STM32F723E_DISCOVERY_AUDIO Private Variables + * @{ + */ +AUDIO_DrvTypeDef *audio_drv; +SAI_HandleTypeDef haudio_out_sai; +SAI_HandleTypeDef haudio_in_sai; + +uint16_t __IO AudioInVolume = DEFAULT_AUDIO_IN_VOLUME; +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO_Private_Function_Prototypes STM32F723E_DISCOVERY_AUDIO Private Function Prototypes + * @{ + */ +static void SAIx_Out_Init(uint32_t AudioFreq); +static void SAIx_Out_DeInit(void); +static void SAIx_In_Init(uint32_t SaiOutMode, uint32_t SlotActive, uint32_t AudioFreq); +static void SAIx_In_DeInit(void); + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO_out_Private_Functions STM32F723E_DISCOVERY_AUDIO_Out Private Functions + * @{ + */ + +/** + * @brief Configures the audio out peripheral(SAI2 BlockA). + * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * or OUTPUT_DEVICE_BOTH. + * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) + * @param AudioFreq: Audio frequency used to play the audio stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + + /* Disable SAI */ + SAIx_Out_DeInit(); + + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); + } + SAIx_Out_Init(AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq); + } + + return ret; +} + +/** + * @brief Starts playing audio stream from a data buffer for a determined size. + * @param pBuffer: Pointer to the buffer + * @param Size: Number of audio data BYTES. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size) +{ + /* Call the audio Codec Play function */ + if(audio_drv->Play(AUDIO_I2C_ADDRESS, pBuffer, Size) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Update the Media layer and enable it for play */ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, DMA_MAX(Size / AUDIODATA_SIZE)); + + return AUDIO_OK; + } +} + +/** + * @brief This function Pauses the audio file stream. In case + * of using DMA, the DMA Pause feature is used. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Pause(void) +{ + /* Call the Audio Codec Pause/Resume function */ + if(audio_drv->Pause(AUDIO_I2C_ADDRESS) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause function */ + HAL_SAI_DMAPause(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief This function Resumes the audio file stream. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Resume(void) +{ + /* Call the Audio Codec Pause/Resume function */ + if(audio_drv->Resume(AUDIO_I2C_ADDRESS) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause/resume function */ + HAL_SAI_DMAResume(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Stops audio playing and Power down the Audio Codec. + * @param Option: could be one of the following parameters + * - CODEC_PDWN_SW: for software power off (by writing registers). + * Then no need to reconfigure the Codec after power on. + * - CODEC_PDWN_HW: completely shut down the codec (physically). + * Then need to reconfigure the Codec after power on. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option) +{ + /* Call the Media layer stop function */ + HAL_SAI_DMAStop(&haudio_out_sai); + + /* Call Audio Codec Stop function */ + if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) + { + return AUDIO_ERROR; + } + else + { + if(Option == CODEC_PDWN_HW) + { + /* Wait at least 100us */ + HAL_Delay(1); + } + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Controls the current audio volume level. + * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for + * Mute and 100 for Max volume level). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume) +{ + /* Call the codec volume control function with converted volume value */ + if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Enables or disables the MUTE mode by software + * @param Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to + * unmute the codec and restore previous volume level. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd) +{ + /* Call the Codec Mute function */ + if(audio_drv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Switch dynamically (while audio file is played) the output target + * (speaker or headphone). + * @param Output: The audio output target: OUTPUT_DEVICE_SPEAKER, + * OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output) +{ + /* Call the Codec output device function */ + if(audio_drv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Updates the audio frequency. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frequency. + * @retval None + */ +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq) +{ + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frequency configuration */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Updates the Audio frame slot configuration. + * @param AudioFrameSlot: specifies the audio Frame slot + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frame slot. + * @retval None + */ +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot) +{ + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frame slot configuration */ + haudio_out_sai.SlotInit.SlotActive = AudioFrameSlot; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Send n-Bytes on the SAI interface. + * @param pData: pointer on data address + * @param Size: number of data to be written + * @retval None + */ +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size) +{ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pData, Size); +} + +/** + * @brief Deinit the audio peripherals. + * @retval None + */ +void BSP_AUDIO_OUT_DeInit(void) +{ + SAIx_Out_DeInit(); + /* DeInit the SAI MSP : this __weak function can be rewritten by the application */ + BSP_AUDIO_OUT_MspDeInit(&haudio_out_sai, NULL); +} + +/** + * @brief Tx Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f723e_discovery_audio.h) */ + BSP_AUDIO_OUT_TransferComplete_CallBack(); +} + +/** + * @brief Tx Half Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f723e_discovery_audio.h) */ + BSP_AUDIO_OUT_HalfTransfer_CallBack(); +} + +/** + * @brief SAI error callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai) +{ + BSP_AUDIO_OUT_Error_CallBack(); +} + +/** + * @brief Manages the DMA full Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void) +{ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void) +{ +} + +/** + * @brief Manages the DMA FIFO error event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_Error_CallBack(void) +{ +} + +/** + * @brief Initializes BSP_AUDIO_OUT MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params) +{ + static DMA_HandleTypeDef hdma_sai_tx; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SAI clock */ + AUDIO_OUT_SAIx_CLK_ENABLE(); + + /* Enable GPIO clock */ + AUDIO_OUT_SAIx_MCLK_ENABLE(); + AUDIO_OUT_SAIx_SD_FS_CLK_ENABLE(); + + /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/ + gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN | AUDIO_OUT_SAIx_SCK_PIN | AUDIO_OUT_SAIx_SD_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_OUT_SAIx_AF; + HAL_GPIO_Init(AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN; + HAL_GPIO_Init(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, &gpio_init_structure); + + /* Enable the DMA clock */ + AUDIO_OUT_SAIx_DMAx_CLK_ENABLE(); + + if(hsai->Instance == AUDIO_OUT_SAIx) + { + /* Configure the hdma_saiTx handle parameters */ + hdma_sai_tx.Init.Channel = AUDIO_OUT_SAIx_DMAx_CHANNEL; + hdma_sai_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_sai_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sai_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sai_tx.Init.PeriphDataAlignment = AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE; + hdma_sai_tx.Init.MemDataAlignment = AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE; + hdma_sai_tx.Init.Mode = DMA_CIRCULAR; + hdma_sai_tx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_sai_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + hdma_sai_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sai_tx.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_sai_tx.Init.PeriphBurst = DMA_PBURST_SINGLE; + + hdma_sai_tx.Instance = AUDIO_OUT_SAIx_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsai, hdmatx, hdma_sai_tx); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_tx); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hdma_sai_tx); + } + + /* SAI DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_OUT_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ); +} + +/** + * @brief Deinitializes SAI MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* SAI DMA IRQ Channel deactivation */ + HAL_NVIC_DisableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ); + + if(hsai->Instance == AUDIO_OUT_SAIx) + { + /* Deinitialize the DMA stream */ + HAL_DMA_DeInit(hsai->hdmatx); + } + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(hsai); + + /* Deactivates CODEC_SAI pins FS, SCK, MCK and SD by putting them in input mode */ + gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN | AUDIO_OUT_SAIx_SCK_PIN | AUDIO_OUT_SAIx_SCK_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, gpio_init_structure.Pin); + + /* Disable SAI clock */ + AUDIO_OUT_SAIx_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the applic + by surcharging this __weak function */ +} + +/** + * @brief Clock Config. + * @param hsai: might be required to set audio peripheral predivider if any. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @param Params + * @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params) +{ + RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; + + HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); + + /* Set the PLL configuration according to the audio frequency */ + if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) + { + /* Configure PLLSAI prescalers */ + /* PLLSAI_VCO: VCO_429M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 429/2 = 214.5 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 214.5/19 = 11.289 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 429; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 2; + rcc_ex_clk_init_struct.PLLI2SDivQ = 19; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + + } + else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */ + { + /* SAI clock config + PLLSAI_VCO: VCO_344M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 344/7 = 49.142 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 49.142/1 = 49.142 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 344; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 7; + rcc_ex_clk_init_struct.PLLI2SDivQ = 1; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + } +} + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Initializes the Audio Codec audio interface (SAI). + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @note The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123 + * and user can update this configuration using + * @retval None + */ +static void SAIx_Out_Init(uint32_t AudioFreq) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_out_sai.Init.MonoStereoMode = SAI_STEREOMODE; + haudio_out_sai.Init.AudioFrequency = AudioFreq; + haudio_out_sai.Init.AudioMode = SAI_MODEMASTER_TX; + haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLED; + haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE; + haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; + haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; + haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + haudio_out_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; + haudio_out_sai.Init.CompandingMode = SAI_NOCOMPANDING; + haudio_out_sai.Init.TriState = SAI_OUTPUT_NOTRELEASED; + haudio_out_sai.Init.Mckdiv = 0; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_out_sai.FrameInit.FrameLength = 64; + haudio_out_sai.FrameInit.ActiveFrameLength = 32; + haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot actives */ + haudio_out_sai.SlotInit.FirstBitOffset = 0; + haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_out_sai.SlotInit.SlotNumber = 4; + haudio_out_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_0123; + + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Deinitializes the Audio Codec audio interface (SAI). + * @retval None + */ +static void SAIx_Out_DeInit(void) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + HAL_SAI_DeInit(&haudio_out_sai); +} + + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO_In_Private_Functions STM32F723E_DISCOVERY_AUDIO_In Private Functions + * @{ + */ + +/** + * @brief Initializes wave recording. + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @param BitRes: Audio frequency to be configured. + * @param ChnlNbr: Channel number. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + return BSP_AUDIO_IN_InitEx(INPUT_DEVICE_DIGITAL_MIC1_MIC2, AudioFreq, BitRes, ChnlNbr); +} + +/** + * @brief Initializes wave recording. + * @param InputDevice: INPUT_DEVICE_DIGITAL_MICROPHONE_1, INPUT_DEVICE_DIGITAL_MICROPHONE_2 + * INPUT_DEVICE_INPUT_LINE_1 or INPUT_DEVICE_DIGITAL_MIC1_MIC2 + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @param BitRes: Audio frequency to be configured. + * @param ChnlNbr: Channel number. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + uint32_t slot_active; + + /* Only INPUT_LINE_1, MICROPHONE_1, MICROPHONE_2 and MIC1&MIC2 inputs supported */ + if ((InputDevice != INPUT_DEVICE_INPUT_LINE_1) && + (InputDevice != INPUT_DEVICE_DIGITAL_MICROPHONE_1) && + (InputDevice != INPUT_DEVICE_DIGITAL_MICROPHONE_2) && + (InputDevice != INPUT_DEVICE_DIGITAL_MIC1_MIC2)) + { + ret = AUDIO_ERROR; + } + else + { + /* Disable SAI */ + SAIx_In_DeInit(); + + /* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_IN_ClockConfig(&haudio_in_sai, AudioFreq, NULL); /* Clock config is shared between AUDIO IN and OUT */ + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from SAI peripheral to memory */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + if(HAL_SAI_GetState(&haudio_in_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_in_sai, NULL); /* Initialize GPIOs for SAI2 block A Master signals */ + BSP_AUDIO_IN_MspInit(&haudio_in_sai, NULL); + } + + /* Configure SAI in master RX mode : + * - SAI2_block_A in master RX mode + * - SAI2_block_B in slave RX mode synchronous from SAI2_block_A + */ + if (InputDevice == INPUT_DEVICE_DIGITAL_MICROPHONE_2) + { + slot_active = CODEC_AUDIOFRAME_SLOT_13; + } + else if (InputDevice == INPUT_DEVICE_DIGITAL_MIC1_MIC2) + { + slot_active = CODEC_AUDIOFRAME_SLOT_0123; + } + else + { + slot_active = CODEC_AUDIOFRAME_SLOT_02; + } + SAIx_In_Init(SAI_MODEMASTER_RX, slot_active, AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, InputDevice, 100, AudioFreq); + } + } + return ret; +} + +/** + * @brief Initializes wave recording and playback in parallel. + * @param InputDevice: INPUT_DEVICE_DIGITAL_MICROPHONE_1, INPUT_DEVICE_DIGITAL_MICROPHONE_2 + * or INPUT_DEVICE_DIGITAL_MIC1_MIC2 + * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * or OUTPUT_DEVICE_BOTH. + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @param BitRes: Audio frequency to be configured. + * @param ChnlNbr: Channel number. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_OUT_Init(uint16_t InputDevice, uint16_t OutputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + uint32_t slot_active; + + if ((InputDevice != INPUT_DEVICE_DIGITAL_MICROPHONE_1) && + (InputDevice != INPUT_DEVICE_DIGITAL_MICROPHONE_2) && + (InputDevice != INPUT_DEVICE_DIGITAL_MIC1_MIC2)) + { + ret = AUDIO_ERROR; + } + else + { + /* Disable SAI */ + SAIx_In_DeInit(); + SAIx_Out_DeInit(); + + /* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_in_sai, AudioFreq, NULL); /* Clock config is shared between AUDIO IN and OUT */ + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from SAI peripheral to memory */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + if(HAL_SAI_GetState(&haudio_in_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_IN_MspInit(&haudio_in_sai, NULL); + } + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); + } + + /* Configure SAI in master mode : + * - SAI2_block_A in master TX mode + * - SAI2_block_B in slave RX mode synchronous from SAI2_block_A + */ + if (InputDevice == INPUT_DEVICE_DIGITAL_MICROPHONE_2) + { + slot_active = CODEC_AUDIOFRAME_SLOT_13; + } + else if (InputDevice == INPUT_DEVICE_DIGITAL_MIC1_MIC2) + { + slot_active = CODEC_AUDIOFRAME_SLOT_0123; + } + else + { + slot_active = CODEC_AUDIOFRAME_SLOT_02; + } + SAIx_In_Init(SAI_MODEMASTER_TX, slot_active, AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, InputDevice | OutputDevice, 100, AudioFreq); + } + } + return ret; +} + +/** + * @brief Starts audio recording. + * @param pbuf: Main buffer pointer for the recorded data storing + * @param size: size of the recorded buffer in number of elements (typically number of half-words) + * Be careful that it is not the same unit than BSP_AUDIO_OUT_Play function + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size) +{ + uint32_t ret = AUDIO_ERROR; + + /* Start the process receive DMA */ + if(HAL_SAI_Receive_DMA(&haudio_in_sai, (uint8_t*)pbuf, size) == HAL_OK) + { + /* Return AUDIO_OK when all operations are correctly done */ + ret = AUDIO_OK; + } + + return ret; +} + +/** + * @brief Stops audio recording. + * @param Option: could be one of the following parameters + * - CODEC_PDWN_SW: for software power off (by writing registers). + * Then no need to reconfigure the Codec after power on. + * - CODEC_PDWN_HW: completely shut down the codec (physically). + * Then need to reconfigure the Codec after power on. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Stop(uint32_t Option) +{ + /* Call the Media layer stop function */ + HAL_SAI_DMAStop(&haudio_in_sai); + + /* Call Audio Codec Stop function */ + if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) + { + return AUDIO_ERROR; + } + else + { + if(Option == CODEC_PDWN_HW) + { + /* Wait at least 100us */ + HAL_Delay(1); + } + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Pauses the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Pause(void) +{ + /* Call the Media layer pause function */ + HAL_SAI_DMAPause(&haudio_in_sai); + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Resumes the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Resume(void) +{ + /* Call the Media layer pause/resume function */ + HAL_SAI_DMAResume(&haudio_in_sai); + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Controls the audio in volume level. + * @param Volume: Volume level in range 0(Mute)..80(+0dB)..100(+17.625dB) + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume) +{ + /* Call the codec volume control function with converted volume value */ + if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Set the Global variable AudioInVolume */ + AudioInVolume = Volume; + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Deinit the audio IN peripherals. + * @retval None + */ +void BSP_AUDIO_IN_DeInit(void) +{ + SAIx_In_DeInit(); + /* DeInit the SAI MSP : this __weak function can be rewritten by the application */ + BSP_AUDIO_IN_MspDeInit(&haudio_in_sai, NULL); +} + + /** + * @brief Rx Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ + BSP_AUDIO_IN_TransferComplete_CallBack(); +} + +/** + * @brief Rx Half Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f723e_discovery_audio.h) */ + BSP_AUDIO_IN_HalfTransfer_CallBack(); +} + +/** + * @brief User callback when record buffer is filled. + * @retval None + */ +__weak void BSP_AUDIO_IN_TransferComplete_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Audio IN Error callback function. + * @retval None + */ +__weak void BSP_AUDIO_IN_Error_CallBack(void) +{ + /* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +} + +/** + * @brief Initializes BSP_AUDIO_IN MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_IN_MspInit(SAI_HandleTypeDef *hsai, void *Params) +{ + static DMA_HandleTypeDef hdma_sai_rx; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SAI clock */ + AUDIO_IN_SAIx_CLK_ENABLE(); + + /* Enable SD GPIO clock */ + AUDIO_IN_SAIx_SD_ENABLE(); + /* CODEC_SAI pin configuration: SD pin */ + gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = AUDIO_IN_SAIx_SD_AF; + HAL_GPIO_Init(AUDIO_IN_SAIx_SD_GPIO_PORT, &gpio_init_structure); + + /* Enable Audio INT GPIO clock */ + AUDIO_IN_INT_GPIO_ENABLE(); + /* Audio INT pin configuration: input */ + gpio_init_structure.Pin = AUDIO_IN_INT_GPIO_PIN; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + HAL_GPIO_Init(AUDIO_IN_INT_GPIO_PORT, &gpio_init_structure); + + /* Enable the DMA clock */ + AUDIO_IN_SAIx_DMAx_CLK_ENABLE(); + + if(hsai->Instance == AUDIO_IN_SAIx) + { + /* Configure the hdma_sai_rx handle parameters */ + hdma_sai_rx.Init.Channel = AUDIO_IN_SAIx_DMAx_CHANNEL; + hdma_sai_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_sai_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sai_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sai_rx.Init.PeriphDataAlignment = AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE; + hdma_sai_rx.Init.MemDataAlignment = AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE; + hdma_sai_rx.Init.Mode = DMA_CIRCULAR; + hdma_sai_rx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_sai_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_sai_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sai_rx.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_sai_rx.Init.PeriphBurst = DMA_MBURST_SINGLE; + + hdma_sai_rx.Instance = AUDIO_IN_SAIx_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsai, hdmarx, hdma_sai_rx); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_rx); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hdma_sai_rx); + } + + /* SAI DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_IN_SAIx_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_IN_SAIx_DMAx_IRQ); + + /* Audio INT IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_IN_INT_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_IN_INT_IRQ); +} + +/** + * @brief DeInitializes BSP_AUDIO_IN MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_IN_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* SAI IN DMA IRQ Channel deactivation */ + HAL_NVIC_DisableIRQ(AUDIO_IN_SAIx_DMAx_IRQ); + + if(hsai->Instance == AUDIO_IN_SAIx) + { + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(haudio_in_sai.hdmarx); + } + + /* Disable SAI block */ + __HAL_SAI_DISABLE(hsai); + + /* Disable pin: SD pin */ + gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN; + HAL_GPIO_DeInit(AUDIO_IN_SAIx_SD_GPIO_PORT, gpio_init_structure.Pin); + + /* Disable SAI clock */ + AUDIO_IN_SAIx_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Clock Config. + * @param hsai: might be required to set audio peripheral predivider if any. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @param Params + * @note This API is called by BSP_AUDIO_IN_Init() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_AUDIO_IN_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params) +{ + RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; + + HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); + + /* Set the PLL configuration according to the audio frequency */ + if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) + { + /* Configure PLLSAI prescalers */ + /* PLLSAI_VCO: VCO_429M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 429/2 = 214.5 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 214.5/19 = 11.289 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 429; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 2; + rcc_ex_clk_init_struct.PLLI2SDivQ = 19; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + + } + else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K), AUDIO_FREQUENCY_96K */ + { + /* SAI clock config + PLLSAI_VCO: VCO_344M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 344/7 = 49.142 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 49.142/1 = 49.142 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 344; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 7; + rcc_ex_clk_init_struct.PLLI2SDivQ = 1; + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + } +} + +/******************************************************************************* + Static Functions +*******************************************************************************/ +/** + * @brief Initializes the input Audio Codec audio interface (SAI). + * @param SaiOutMode: SAI_MODEMASTER_TX (for record and playback in parallel) + * or SAI_MODEMASTER_RX (for record only). + * @param SlotActive: CODEC_AUDIOFRAME_SLOT_02, CODEC_AUDIOFRAME_SLOT_13 or + * CODEC_AUDIOFRAME_SLOT_0123 + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @retval None + */ +static void SAIx_In_Init(uint32_t SaiOutMode, uint32_t SlotActive, uint32_t AudioFreq) +{ + /* Initialize the haudio_out_sai instance parameters */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + haudio_out_sai.Init.AudioMode = SaiOutMode; + haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; + haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE; + haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; + haudio_out_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; + haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; + haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + haudio_out_sai.Init.Mckdiv = 0; + haudio_out_sai.Init.MonoStereoMode = SAI_STEREOMODE; + haudio_out_sai.Init.CompandingMode = SAI_NOCOMPANDING; + haudio_out_sai.Init.TriState = SAI_OUTPUT_NOTRELEASED; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_out_sai.FrameInit.FrameLength = 64; + haudio_out_sai.FrameInit.ActiveFrameLength = 32; + haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot actives */ + haudio_out_sai.SlotInit.FirstBitOffset = 0; + haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_out_sai.SlotInit.SlotNumber = 4; + haudio_out_sai.SlotInit.SlotActive = SlotActive; + + HAL_SAI_Init(&haudio_out_sai); + + /* Initialize SAI2 block B in SLAVE RX synchronous from SAI2 block A */ + /* Initialize the haudio_in_sai instance parameters */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_in_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_in_sai.Init.AudioFrequency = AudioFreq; + haudio_in_sai.Init.AudioMode = SAI_MODESLAVE_RX; + haudio_in_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; + haudio_in_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_in_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_in_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_in_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; + haudio_in_sai.Init.Synchro = SAI_SYNCHRONOUS; + haudio_in_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; + haudio_in_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; + haudio_in_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + haudio_in_sai.Init.Mckdiv = 0; + haudio_in_sai.Init.MonoStereoMode = SAI_STEREOMODE; + haudio_in_sai.Init.CompandingMode = SAI_NOCOMPANDING; + haudio_in_sai.Init.TriState = SAI_OUTPUT_NOTRELEASED; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_in_sai.FrameInit.FrameLength = 64; + haudio_in_sai.FrameInit.ActiveFrameLength = 32; + haudio_in_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_in_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_in_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot active */ + haudio_in_sai.SlotInit.FirstBitOffset = 0; + haudio_in_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_in_sai.SlotInit.SlotNumber = 4; + haudio_in_sai.SlotInit.SlotActive = SlotActive; + + HAL_SAI_Init(&haudio_in_sai); + + /* Enable SAI peripheral */ + __HAL_SAI_ENABLE(&haudio_in_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + + + +/** + * @brief Deinitializes the output Audio Codec audio interface (SAI). + * @retval None + */ +static void SAIx_In_DeInit(void) +{ + /* Initialize the haudio_in_sai Instance parameter */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(&haudio_in_sai); + + HAL_SAI_DeInit(&haudio_in_sai); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_audio.h b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_audio.h new file mode 100644 index 00000000..cf78a388 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_audio.h @@ -0,0 +1,320 @@ +/** + ****************************************************************************** + * @file stm32f723e_discovery_audio.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f723e_discovery_audio.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F723E_DISCOVERY_AUDIO_H +#define __STM32F723E_DISCOVERY_AUDIO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include audio component Driver */ +#include "../Components/wm8994/wm8994.h" +#include "stm32f723e_discovery.h" +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO STM32F723E_DISCOVERY_AUDIO + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO_Exported_Types STM32F723E_DISCOVERY_AUDIO Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO_Exported_Constants STM32F723E_DISCOVERY_AUDIO Exported Constants + * @{ + */ + +/** @defgroup BSP_Audio_Out_Option BSP Audio Out Option + * @{ + */ +#define BSP_AUDIO_OUT_CIRCULARMODE ((uint32_t)0x00000001) /* BUFFER CIRCULAR MODE */ +#define BSP_AUDIO_OUT_NORMALMODE ((uint32_t)0x00000002) /* BUFFER NORMAL MODE */ +#define BSP_AUDIO_OUT_STEREOMODE ((uint32_t)0x00000004) /* STEREO MODE */ +#define BSP_AUDIO_OUT_MONOMODE ((uint32_t)0x00000008) /* MONO MODE */ +/** + * @} + */ +/** @defgroup BSP_Audio_Sample_Rate BSP Audio Sample Rate + * @{ + */ +#define BSP_AUDIO_FREQUENCY_96K SAI_AUDIO_FREQUENCY_96K +#define BSP_AUDIO_FREQUENCY_48K SAI_AUDIO_FREQUENCY_48K +#define BSP_AUDIO_FREQUENCY_44K SAI_AUDIO_FREQUENCY_44K +#define BSP_AUDIO_FREQUENCY_32K SAI_AUDIO_FREQUENCY_32K +#define BSP_AUDIO_FREQUENCY_22K SAI_AUDIO_FREQUENCY_22K +#define BSP_AUDIO_FREQUENCY_16K SAI_AUDIO_FREQUENCY_16K +#define BSP_AUDIO_FREQUENCY_11K SAI_AUDIO_FREQUENCY_11K +#define BSP_AUDIO_FREQUENCY_8K SAI_AUDIO_FREQUENCY_8K +/** + * @} + */ + +/*------------------------------------------------------------------------------ + USER SAI defines parameters + -----------------------------------------------------------------------------*/ +/** CODEC_AudioFrame_SLOT_TDMMode In W8994 codec the Audio frame contains 4 slots : TDM Mode + * TDM format : + * +------------------|------------------|--------------------|-------------------+ + * | CODEC_SLOT0 Left | CODEC_SLOT1 Left | CODEC_SLOT0 Right | CODEC_SLOT1 Right | + * +------------------------------------------------------------------------------+ + */ +/* To have 2 separate audio stream in Both headphone and speaker the 4 slot must be activated */ +#define CODEC_AUDIOFRAME_SLOT_0123 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_2 | SAI_SLOTACTIVE_3 + +/* To have an audio stream in headphone only SAI Slot 0 and Slot 2 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_02 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_2 +/* To have an audio stream in speaker only SAI Slot 1 and Slot 3 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_13 SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_3 + + +/* SAI peripheral configuration defines */ +#define AUDIO_OUT_SAIx SAI2_Block_A +#define AUDIO_OUT_SAIx_CLK_ENABLE() __HAL_RCC_SAI2_CLK_ENABLE() +#define AUDIO_OUT_SAIx_CLK_DISABLE() __HAL_RCC_SAI2_CLK_DISABLE() +#define AUDIO_OUT_SAIx_AF GPIO_AF10_SAI2 + +#define AUDIO_OUT_SAIx_MCLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define AUDIO_OUT_SAIx_MCLK_GPIO_PORT GPIOI +#define AUDIO_OUT_SAIx_MCLK_PIN GPIO_PIN_4 +#define AUDIO_OUT_SAIx_SD_FS_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT GPIOI +#define AUDIO_OUT_SAIx_FS_PIN GPIO_PIN_7 +#define AUDIO_OUT_SAIx_SCK_PIN GPIO_PIN_5 +#define AUDIO_OUT_SAIx_SD_PIN GPIO_PIN_6 + +/* SAI DMA Stream definitions */ +#define AUDIO_OUT_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_OUT_SAIx_DMAx_STREAM DMA2_Stream4 +#define AUDIO_OUT_SAIx_DMAx_CHANNEL DMA_CHANNEL_3 +#define AUDIO_OUT_SAIx_DMAx_IRQ DMA2_Stream4_IRQn +#define AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD +#define AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD +#define DMA_MAX_SZE 0xFFFF + +#define AUDIO_OUT_SAIx_DMAx_IRQHandler DMA2_Stream4_IRQHandler + +/* Select the interrupt preemption priority for the DMA interrupt */ +#define AUDIO_OUT_IRQ_PREPRIO ((uint32_t)0x0E) /* Select the preemption priority level(0 is the highest) */ + +/*------------------------------------------------------------------------------ + AUDIO IN CONFIGURATION +------------------------------------------------------------------------------*/ +/* SAI IN peripheral configuration defines */ +#define AUDIO_IN_SAIx SAI2_Block_B +#define AUDIO_IN_SAIx_CLK_ENABLE() __HAL_RCC_SAI2_CLK_ENABLE() +#define AUDIO_IN_SAIx_CLK_DISABLE() __HAL_RCC_SAI2_CLK_DISABLE() +#define AUDIO_IN_SAIx_SD_AF GPIO_AF10_SAI2 + +#define AUDIO_IN_SAIx_SD_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE() +#define AUDIO_IN_SAIx_SD_GPIO_PORT GPIOG +#define AUDIO_IN_SAIx_SD_PIN GPIO_PIN_10 + +#define AUDIO_IN_INT_GPIO_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE() +#define AUDIO_IN_INT_GPIO_PORT GPIOG +#define AUDIO_IN_INT_GPIO_PIN GPIO_PIN_15 +#define AUDIO_IN_INT_IRQ EXTI15_10_IRQn + +/* SAI DMA Stream definitions */ +#define AUDIO_IN_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_IN_SAIx_DMAx_STREAM DMA2_Stream6 +#define AUDIO_IN_SAIx_DMAx_CHANNEL DMA_CHANNEL_3 +#define AUDIO_IN_SAIx_DMAx_IRQ DMA2_Stream6_IRQn +#define AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD +#define AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD + +#define AUDIO_IN_SAIx_DMAx_IRQHandler DMA2_Stream6_IRQHandler +#define AUDIO_IN_INT_IRQHandler EXTI15_10_IRQHandler + +/* Select the interrupt preemption priority and subpriority for the IT/DMA interrupt */ +#define AUDIO_IN_IRQ_PREPRIO ((uint32_t)0x0F) /* Select the preemption priority level(0 is the highest) */ + + +/*------------------------------------------------------------------------------ + CONFIGURATION: Audio Driver Configuration parameters +------------------------------------------------------------------------------*/ + +#define AUDIODATA_SIZE 2 /* 16-bits audio data size */ + +/* Audio status definition */ +#define AUDIO_OK ((uint8_t)0) +#define AUDIO_ERROR ((uint8_t)1) +#define AUDIO_TIMEOUT ((uint8_t)2) + +/* AudioFreq * DataSize (2 bytes) * NumChannels (Stereo: 2) */ +#define DEFAULT_AUDIO_IN_FREQ BSP_AUDIO_FREQUENCY_16K +#define DEFAULT_AUDIO_IN_BIT_RESOLUTION ((uint8_t)16) +#define DEFAULT_AUDIO_IN_CHANNEL_NBR ((uint8_t)2) /* Mono = 1, Stereo = 2 */ +#define DEFAULT_AUDIO_IN_VOLUME ((uint16_t)64) + +/*------------------------------------------------------------------------------ + OPTIONAL Configuration defines parameters +------------------------------------------------------------------------------*/ + +/* Delay for the Codec to be correctly reset */ +#define CODEC_RESET_DELAY ((uint8_t)5) + + +/*------------------------------------------------------------------------------ + OUTPUT DEVICES definition +------------------------------------------------------------------------------*/ +/* Alias on existing output devices to adapt to headphones output */ +#define OUTPUT_DEVICE_HEADPHONE1 OUTPUT_DEVICE_HEADPHONE +#define OUTPUT_DEVICE_HEADPHONE2 OUTPUT_DEVICE_SPEAKER + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO_Exported_Variables STM32F723E_DISCOVERY_AUDIO Exported Variables + * @{ + */ + /** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO_Exported_Macros STM32F723E_DISCOVERY_AUDIO Exported Macros + * @{ + */ +#define DMA_MAX(x) (((x) <= DMA_MAX_SZE)? (x):DMA_MAX_SZE) +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO_OUT_Exported_Functions STM32F723E_DISCOVERY_AUDIO_OUT Exported Functions + * @{ + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq); +void BSP_AUDIO_OUT_DeInit(void); +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size); +uint8_t BSP_AUDIO_OUT_Pause(void); +uint8_t BSP_AUDIO_OUT_Resume(void); +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option); +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume); +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq); +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot); +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd); +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output); +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size); + +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function is called when the requested data has been completely transferred.*/ +void BSP_AUDIO_OUT_TransferComplete_CallBack(void); + +/* This function is called when half of the requested buffer has been transferred. */ +void BSP_AUDIO_OUT_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_OUT_Error_CallBack(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params); +void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params); +void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_AUDIO_IN_Exported_Functions STM32F723E_DISCOVERY_AUDIO_IN Exported Functions + * @{ + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_OUT_Init(uint16_t InputDevice, uint16_t OutputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +void BSP_AUDIO_IN_DeInit(void); +uint8_t BSP_AUDIO_IN_Record(uint16_t *pData, uint32_t Size); +uint8_t BSP_AUDIO_IN_Stop(uint32_t Option); +uint8_t BSP_AUDIO_IN_Pause(void); +uint8_t BSP_AUDIO_IN_Resume(void); +uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume); +void BSP_AUDIO_IN_DeInit(void); + +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled to prepare the next + buffer pointer and its size. */ +void BSP_AUDIO_IN_TransferComplete_CallBack(void); +void BSP_AUDIO_IN_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_IN_Error_CallBack(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_IN_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params); +void BSP_AUDIO_IN_MspInit(SAI_HandleTypeDef *hsai, void *Params); +void BSP_AUDIO_IN_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F723E_DISCOVERY_AUDIO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_lcd.c b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_lcd.c new file mode 100644 index 00000000..b16be830 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_lcd.c @@ -0,0 +1,1182 @@ +/** + ****************************************************************************** + * @file stm32f723e_discovery_lcd.c + * @author MCD Application Team + * @brief This file includes the driver for Liquid Crystal Display (LCD) module + * mounted on STM32F723E-DISCOVERY board. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + +/* File Info : ----------------------------------------------------------------- + User NOTES +1. How To use this driver: +-------------------------- + - This driver is used to drive indirectly an LCD TFT. + - This driver supports the ST7789H2 LCD. + - The ST7789H2 component driver MUST be included with this driver. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the LCD using the BSP_LCD_Init() function. + + + Display on LCD + o Clear the hole LCD using BSP_LCD_Clear() function or only one specified string + line using the BSP_LCD_ClearStringLine() function. + o Display a character on the specified line and column using the BSP_LCD_DisplayChar() + function or a complete string line using the BSP_LCD_DisplayStringAtLine() function. + o Display a string line on the specified position (x,y in pixel) and align mode + using the BSP_LCD_DisplayStringAtLine() function. + o Draw and fill a basic shapes (dot, line, rectangle, circle, ellipse, .. bitmap) + on LCD using the available set of functions. + +------------------------------------------------------------------------------*/ + +/* Dependencies +- stm32f723e_discovery.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_sram.c +- stm32f7xx_hal_rcc_ex.h +- st7789h2.c +- fonts.h +- font24.c +- font20.c +- font16.c +- font12.c +- font8.c" +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f723e_discovery_lcd.h" +#include "../../../Utilities/Fonts/fonts.h" +#include "../../../Utilities/Fonts/font24.c" +#include "../../../Utilities/Fonts/font20.c" +#include "../../../Utilities/Fonts/font16.c" +#include "../../../Utilities/Fonts/font12.c" +#include "../../../Utilities/Fonts/font8.c" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_LCD STM32F723E-DISCOVERY LCD + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_LCD_Private_TypesDefinitions STM32F723E Discovery Lcd Private TypesDef + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LCD_Private_Defines STM32F723E Discovery Lcd Private Defines + * @{ + */ +#define POLY_X(Z) ((int32_t)((Points + Z)->X)) +#define POLY_Y(Z) ((int32_t)((Points + Z)->Y)) +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LCD_Private_Macros STM32F723E Discovery Lcd Private Macros + * @{ + */ +#define ABS(X) ((X) > 0 ? (X) : -(X)) +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LCD_Private_Variables STM32F723E Discovery Lcd Private Variables + * @{ + */ +LCD_DrawPropTypeDef DrawProp; +static LCD_DrvTypeDef *LcdDrv; + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LCD_Private_FunctionPrototypes STM32F723E Discovery Lcd Private Prototypes + * @{ + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c); +static void SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3); +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LCD_Private_Functions STM32F723E Discovery Lcd Private Functions + * @{ + */ +/** + * @brief Initializes the LCD. + * @retval LCD state + */ +uint8_t BSP_LCD_Init(void) +{ + return (BSP_LCD_InitEx(LCD_ORIENTATION_LANDSCAPE)); +} +/** + * @brief Initializes the LCD with a given orientation. + * @param orientation: LCD_ORIENTATION_PORTRAIT or LCD_ORIENTATION_LANDSCAPE + * @retval LCD state + */ +uint8_t BSP_LCD_InitEx(uint32_t orientation) +{ + uint8_t ret = LCD_ERROR; + + /* Default value for draw propriety */ + DrawProp.BackColor = 0xFFFF; + DrawProp.pFont = &Font24; + DrawProp.TextColor = 0x0000; + + /* Initialize LCD special pins GPIOs */ + BSP_LCD_MspInit(); + + /* Backlight control signal assertion */ + HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_PORT, LCD_BL_CTRL_PIN, GPIO_PIN_SET); + + /* Apply hardware reset according to procedure indicated in FRD154BP2901 documentation */ + HAL_GPIO_WritePin(LCD_RESET_GPIO_PORT, LCD_RESET_PIN, GPIO_PIN_RESET); + HAL_Delay(5); /* Reset signal asserted during 5ms */ + HAL_GPIO_WritePin(LCD_RESET_GPIO_PORT, LCD_RESET_PIN, GPIO_PIN_SET); + HAL_Delay(10); /* Reset signal released during 10ms */ + HAL_GPIO_WritePin(LCD_RESET_GPIO_PORT, LCD_RESET_PIN, GPIO_PIN_RESET); + HAL_Delay(20); /* Reset signal asserted during 20ms */ + HAL_GPIO_WritePin(LCD_RESET_GPIO_PORT, LCD_RESET_PIN, GPIO_PIN_SET); + HAL_Delay(10); /* Reset signal released during 10ms */ + + if(ST7789H2_drv.ReadID() == ST7789H2_ID) + { + LcdDrv = &ST7789H2_drv; + + /* LCD Init */ + LcdDrv->Init(); + + if(orientation == LCD_ORIENTATION_PORTRAIT) + { + ST7789H2_SetOrientation(LCD_ORIENTATION_PORTRAIT); + } + else if(orientation == LCD_ORIENTATION_LANDSCAPE_ROT180) + { + ST7789H2_SetOrientation(LCD_ORIENTATION_LANDSCAPE_ROT180); + } + else + { + /* Default landscape orientation is selected */ + } + /* Initialize the font */ + BSP_LCD_SetFont(&LCD_DEFAULT_FONT); + + ret = LCD_OK; + } + + return ret; +} + +/** + * @brief DeInitializes the LCD. + * @retval LCD state + */ +uint8_t BSP_LCD_DeInit(void) +{ + /* Actually LcdDrv does not provide a DeInit function */ + return LCD_OK; +} + +/** + * @brief Gets the LCD X size. + * @retval Used LCD X size + */ +uint32_t BSP_LCD_GetXSize(void) +{ + return(LcdDrv->GetLcdPixelWidth()); +} + +/** + * @brief Gets the LCD Y size. + * @retval Used LCD Y size + */ +uint32_t BSP_LCD_GetYSize(void) +{ + return(LcdDrv->GetLcdPixelHeight()); +} + +/** + * @brief Gets the LCD text color. + * @retval Used text color. + */ +uint16_t BSP_LCD_GetTextColor(void) +{ + return DrawProp.TextColor; +} + +/** + * @brief Gets the LCD background color. + * @retval Used background color + */ +uint16_t BSP_LCD_GetBackColor(void) +{ + return DrawProp.BackColor; +} + +/** + * @brief Sets the LCD text color. + * @param Color: Text color code RGB(5-6-5) + * @retval None + */ +void BSP_LCD_SetTextColor(uint16_t Color) +{ + DrawProp.TextColor = Color; +} + +/** + * @brief Sets the LCD background color. + * @param Color: Background color code RGB(5-6-5) + * @retval None + */ +void BSP_LCD_SetBackColor(uint16_t Color) +{ + DrawProp.BackColor = Color; +} + +/** + * @brief Sets the LCD text font. + * @param fonts: Font to be used + * @retval None + */ +void BSP_LCD_SetFont(sFONT *fonts) +{ + DrawProp.pFont = fonts; +} + +/** + * @brief Gets the LCD text font. + * @retval Used font + */ +sFONT *BSP_LCD_GetFont(void) +{ + return DrawProp.pFont; +} + +/** + * @brief Clears the hole LCD. + * @param Color: Color of the background + * @retval None + */ +void BSP_LCD_Clear(uint16_t Color) +{ + uint32_t counter = 0; + uint32_t y_size = 0; + uint32_t color_backup = DrawProp.TextColor; + + DrawProp.TextColor = Color; + y_size = BSP_LCD_GetYSize(); + + for(counter = 0; counter < y_size; counter++) + { + BSP_LCD_DrawHLine(0, counter, BSP_LCD_GetXSize()); + } + DrawProp.TextColor = color_backup; + BSP_LCD_SetTextColor(DrawProp.TextColor); +} + +/** + * @brief Clears the selected line. + * @param Line: Line to be cleared + * This parameter can be one of the following values: + * @arg 0..9: if the Current fonts is Font16x24 + * @arg 0..19: if the Current fonts is Font12x12 or Font8x12 + * @arg 0..29: if the Current fonts is Font8x8 + * @retval None + */ +void BSP_LCD_ClearStringLine(uint16_t Line) +{ + uint32_t color_backup = DrawProp.TextColor; + + DrawProp.TextColor = DrawProp.BackColor; + + /* Draw a rectangle with background color */ + BSP_LCD_FillRect(0, (Line * DrawProp.pFont->Height), BSP_LCD_GetXSize(), DrawProp.pFont->Height); + + DrawProp.TextColor = color_backup; + BSP_LCD_SetTextColor(DrawProp.TextColor); +} + +/** + * @brief Displays one character. + * @param Xpos: Start column address + * @param Ypos: Line where to display the character shape. + * @param Ascii: Character ascii code + * This parameter must be a number between Min_Data = 0x20 and Max_Data = 0x7E + * @retval None + */ +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii) +{ + DrawChar(Xpos, Ypos, &DrawProp.pFont->table[(Ascii-' ') *\ + DrawProp.pFont->Height * ((DrawProp.pFont->Width + 7) / 8)]); +} + +/** + * @brief Displays characters on the LCD. + * @param Xpos: X position (in pixel) + * @param Ypos: Y position (in pixel) + * @param Text: Pointer to string to display on LCD + * @param Mode: Display mode + * This parameter can be one of the following values: + * @arg CENTER_MODE + * @arg RIGHT_MODE + * @arg LEFT_MODE + * @retval None + */ +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Line_ModeTypdef Mode) +{ + uint16_t refcolumn = 1, i = 0; + uint32_t size = 0, xsize = 0; + uint8_t *ptr = Text; + + /* Get the text size */ + while (*ptr++) size ++ ; + + /* Characters number per line */ + xsize = (BSP_LCD_GetXSize()/DrawProp.pFont->Width); + + switch (Mode) + { + case CENTER_MODE: + { + refcolumn = Xpos + ((xsize - size)* DrawProp.pFont->Width) / 2; + break; + } + case LEFT_MODE: + { + refcolumn = Xpos; + break; + } + case RIGHT_MODE: + { + refcolumn = - Xpos + ((xsize - size)*DrawProp.pFont->Width); + break; + } + default: + { + refcolumn = Xpos; + break; + } + } + + /* Check that the Start column is located in the screen */ + if ((refcolumn < 1) || (refcolumn >= 0x8000)) + { + refcolumn = 1; + } + + /* Send the string character by character on lCD */ + while ((*Text != 0) & (((BSP_LCD_GetXSize() - (i*DrawProp.pFont->Width)) & 0xFFFF) >= DrawProp.pFont->Width)) + { + /* Display one character on LCD */ + BSP_LCD_DisplayChar(refcolumn, Ypos, *Text); + /* Decrement the column position by 16 */ + refcolumn += DrawProp.pFont->Width; + /* Point on the next character */ + Text++; + i++; + } +} + +/** + * @brief Displays a character on the LCD. + * @param Line: Line where to display the character shape + * This parameter can be one of the following values: + * @arg 0..9: if the Current fonts is Font16x24 + * @arg 0..19: if the Current fonts is Font12x12 or Font8x12 + * @arg 0..29: if the Current fonts is Font8x8 + * @param ptr: Pointer to string to display on LCD + * @retval None + */ +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr) +{ + BSP_LCD_DisplayStringAt(0, LINE(Line), ptr, LEFT_MODE); +} + +/** + * @brief Reads an LCD pixel. + * @param Xpos: X position + * @param Ypos: Y position + * @retval RGB pixel color + */ +uint16_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos) +{ + uint16_t ret = 0; + + if(LcdDrv->ReadPixel != NULL) + { + ret = LcdDrv->ReadPixel(Xpos, Ypos); + } + + return ret; +} + +/** + * @brief Draws a pixel on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param RGB_Code: Pixel color in RGB mode (5-6-5) + * @retval None + */ +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGB_Code) +{ + if(LcdDrv->WritePixel != NULL) + { + LcdDrv->WritePixel(Xpos, Ypos, RGB_Code); + } +} + +/** + * @brief Draws an horizontal line. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + * @retval None + */ +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t index = 0; + + if(LcdDrv->DrawHLine != NULL) + { + LcdDrv->DrawHLine(DrawProp.TextColor, Xpos, Ypos, Length); + } + else + { + for(index = 0; index < Length; index++) + { + BSP_LCD_DrawPixel((Xpos + index), Ypos, DrawProp.TextColor); + } + } +} + +/** + * @brief Draws a vertical line. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + * @retval None + */ +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t index = 0; + + if(LcdDrv->DrawVLine != NULL) + { + LcdDrv->DrawVLine(DrawProp.TextColor, Xpos, Ypos, Length); + } + else + { + for(index = 0; index < Length; index++) + { + BSP_LCD_DrawPixel(Xpos, Ypos + index, DrawProp.TextColor); + } + } +} + +/** + * @brief Draws an uni-line (between two points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @retval None + */ +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + numadd = deltay; + numpixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + numadd = deltax; + numpixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= numpixels; curpixel++) + { + BSP_LCD_DrawPixel(x, y, DrawProp.TextColor); /* Draw the current pixel */ + num += numadd; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Draws a rectangle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + * @retval None + */ +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Draw horizontal lines */ + BSP_LCD_DrawHLine(Xpos, Ypos, Width); + BSP_LCD_DrawHLine(Xpos, (Ypos+ Height), Width); + + /* Draw vertical lines */ + BSP_LCD_DrawVLine(Xpos, Ypos, Height); + BSP_LCD_DrawVLine((Xpos + Width), Ypos, Height); +} + +/** + * @brief Draws a circle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + * @retval None + */ +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t decision; /* Decision Variable */ + uint32_t current_x; /* Current X Value */ + uint32_t current_y; /* Current Y Value */ + + decision = 3 - (Radius << 1); + current_x = 0; + current_y = Radius; + + while (current_x <= current_y) + { + BSP_LCD_DrawPixel((Xpos + current_x), (Ypos - current_y), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos - current_x), (Ypos - current_y), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos + current_y), (Ypos - current_x), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos - current_y), (Ypos - current_x), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos + current_x), (Ypos + current_y), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos - current_x), (Ypos + current_y), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos + current_y), (Ypos + current_x), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos - current_y), (Ypos + current_x), DrawProp.TextColor); + + /* Initialize the font */ + BSP_LCD_SetFont(&LCD_DEFAULT_FONT); + + if (decision < 0) + { + decision += (current_x << 2) + 6; + } + else + { + decision += ((current_x - current_y) << 2) + 10; + current_y--; + } + current_x++; + } +} + +/** + * @brief Draws an poly-line (between many points). + * @param Points: Pointer to the points array + * @param PointCount: Number of points + * @retval None + */ +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t x = 0, y = 0; + + if(PointCount < 2) + { + return; + } + + BSP_LCD_DrawLine(Points->X, Points->Y, (Points+PointCount-1)->X, (Points+PointCount-1)->Y); + + while(--PointCount) + { + x = Points->X; + y = Points->Y; + Points++; + BSP_LCD_DrawLine(x, y, Points->X, Points->Y); + } +} + +/** + * @brief Draws an ellipse on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + * @retval None + */ +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float k = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + k = (float)(rad2/rad1); + + do { + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/k)), (Ypos+y), DrawProp.TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/k)), (Ypos+y), DrawProp.TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/k)), (Ypos-y), DrawProp.TextColor); + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/k)), (Ypos-y), DrawProp.TextColor); + + e2 = err; + if (e2 <= x) { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Draws a bitmap picture (16 bpp). + * @param Xpos: Bmp X position in the LCD + * @param Ypos: Bmp Y position in the LCD + * @param pbmp: Pointer to Bmp picture address. + * @retval None + */ +void BSP_LCD_DrawBitmap(uint16_t Xpos, uint16_t Ypos, uint8_t *pbmp) +{ + uint32_t height = 0; + uint32_t width = 0; + + /* Read bitmap width */ + width = pbmp[18] + (pbmp[19] << 8) + (pbmp[20] << 16) + (pbmp[21] << 24); + + /* Read bitmap height */ + height = pbmp[22] + (pbmp[23] << 8) + (pbmp[24] << 16) + (pbmp[25] << 24); + + SetDisplayWindow(Xpos, Ypos, width, height); + + if(LcdDrv->DrawBitmap != NULL) + { + LcdDrv->DrawBitmap(Xpos, Ypos, pbmp); + } + SetDisplayWindow(0, 0, BSP_LCD_GetXSize(), BSP_LCD_GetYSize()); +} + +/** + * @brief Draws RGB Image (16 bpp). + * @param Xpos: X position in the LCD + * @param Ypos: Y position in the LCD + * @param Xsize: X size in the LCD + * @param Ysize: Y size in the LCD + * @param pdata: Pointer to the RGB Image address. + * @retval None + */ +void BSP_LCD_DrawRGBImage(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint16_t Ysize, uint8_t *pdata) +{ + + SetDisplayWindow(Xpos, Ypos, Xsize, Ysize); + + if(LcdDrv->DrawRGBImage != NULL) + { + LcdDrv->DrawRGBImage(Xpos, Ypos, Xsize, Ysize, pdata); + } + SetDisplayWindow(0, 0, BSP_LCD_GetXSize(), BSP_LCD_GetYSize()); +} + +/** + * @brief Draws a full rectangle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + * @retval None + */ +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + BSP_LCD_SetTextColor(DrawProp.TextColor); + do + { + BSP_LCD_DrawHLine(Xpos, Ypos++, Width); + } + while(Height--); +} + +/** + * @brief Draws a full circle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + * @retval None + */ +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t decision; /* Decision Variable */ + uint32_t current_x; /* Current X Value */ + uint32_t current_y; /* Current Y Value */ + + decision = 3 - (Radius << 1); + + current_x = 0; + current_y = Radius; + + BSP_LCD_SetTextColor(DrawProp.TextColor); + + while (current_x <= current_y) + { + if(current_y > 0) + { + BSP_LCD_DrawHLine(Xpos - current_y, Ypos + current_x, 2*current_y); + BSP_LCD_DrawHLine(Xpos - current_y, Ypos - current_x, 2*current_y); + } + + if(current_x > 0) + { + BSP_LCD_DrawHLine(Xpos - current_x, Ypos - current_y, 2*current_x); + BSP_LCD_DrawHLine(Xpos - current_x, Ypos + current_y, 2*current_x); + } + if (decision < 0) + { + decision += (current_x << 2) + 6; + } + else + { + decision += ((current_x - current_y) << 2) + 10; + current_y--; + } + current_x++; + } + + BSP_LCD_SetTextColor(DrawProp.TextColor); + BSP_LCD_DrawCircle(Xpos, Ypos, Radius); +} + +/** + * @brief Draws a full poly-line (between many points). + * @param Points: Pointer to the points array + * @param PointCount: Number of points + * @retval None + */ +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t X = 0, Y = 0, X2 = 0, Y2 = 0, X_center = 0, Y_center = 0, X_first = 0, Y_first = 0, pixelX = 0, pixelY = 0, counter = 0; + uint16_t IMAGE_LEFT = 0, IMAGE_RIGHT = 0, IMAGE_TOP = 0, IMAGE_BOTTOM = 0; + + IMAGE_LEFT = IMAGE_RIGHT = Points->X; + IMAGE_TOP= IMAGE_BOTTOM = Points->Y; + + for(counter = 1; counter < PointCount; counter++) + { + pixelX = POLY_X(counter); + if(pixelX < IMAGE_LEFT) + { + IMAGE_LEFT = pixelX; + } + if(pixelX > IMAGE_RIGHT) + { + IMAGE_RIGHT = pixelX; + } + + pixelY = POLY_Y(counter); + if(pixelY < IMAGE_TOP) + { + IMAGE_TOP = pixelY; + } + if(pixelY > IMAGE_BOTTOM) + { + IMAGE_BOTTOM = pixelY; + } + } + + if(PointCount < 2) + { + return; + } + + X_center = (IMAGE_LEFT + IMAGE_RIGHT)/2; + Y_center = (IMAGE_BOTTOM + IMAGE_TOP)/2; + + X_first = Points->X; + Y_first = Points->Y; + + while(--PointCount) + { + X = Points->X; + Y = Points->Y; + Points++; + X2 = Points->X; + Y2 = Points->Y; + + FillTriangle(X, X2, X_center, Y, Y2, Y_center); + FillTriangle(X, X_center, X2, Y, Y_center, Y2); + FillTriangle(X_center, X2, X, Y_center, Y2, Y); + } + + FillTriangle(X_first, X2, X_center, Y_first, Y2, Y_center); + FillTriangle(X_first, X_center, X2, Y_first, Y_center, Y2); + FillTriangle(X_center, X2, X_first, Y_center, Y2, Y_first); +} + +/** + * @brief Draws a full ellipse. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + * @retval None + */ +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float k = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + k = (float)(rad2/rad1); + + do + { + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/k)), (Ypos+y), (2*(uint16_t)(x/k) + 1)); + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/k)), (Ypos-y), (2*(uint16_t)(x/k) + 1)); + + e2 = err; + if (e2 <= x) + { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Enables the display. + * @retval None + */ +void BSP_LCD_DisplayOn(void) +{ + LcdDrv->DisplayOn(); +} + +/** + * @brief Disables the display. + * @retval None + */ +void BSP_LCD_DisplayOff(void) +{ + LcdDrv->DisplayOff(); +} + + +/** + * @brief Initializes the LCD GPIO special pins MSP. + * @retval None + */ +__weak void BSP_LCD_MspInit(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable GPIOs clock */ + LCD_RESET_GPIO_CLK_ENABLE(); + LCD_TE_GPIO_CLK_ENABLE(); + LCD_BL_CTRL_GPIO_CLK_ENABLE(); + + /* LCD_RESET GPIO configuration */ + gpio_init_structure.Pin = LCD_RESET_PIN; /* LCD_RESET pin has to be manually controlled */ + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + HAL_GPIO_Init(LCD_RESET_GPIO_PORT, &gpio_init_structure); + HAL_GPIO_WritePin( LCD_RESET_GPIO_PORT, LCD_RESET_PIN, GPIO_PIN_RESET); + + /* LCD_TE GPIO configuration */ + gpio_init_structure.Pin = LCD_TE_PIN; /* LCD_TE pin has to be manually managed */ + gpio_init_structure.Mode = GPIO_MODE_INPUT; + HAL_GPIO_Init(LCD_TE_GPIO_PORT, &gpio_init_structure); + + /* LCD_BL_CTRL GPIO configuration */ + gpio_init_structure.Pin = LCD_BL_CTRL_PIN; /* LCD_BL_CTRL pin has to be manually controlled */ + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(LCD_BL_CTRL_GPIO_PORT, &gpio_init_structure); +} + +/** + * @brief DeInitializes LCD GPIO special pins MSP. + * @retval None + */ +__weak void BSP_LCD_MspDeInit(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* LCD_RESET GPIO deactivation */ + gpio_init_structure.Pin = LCD_RESET_PIN; + HAL_GPIO_DeInit(LCD_RESET_GPIO_PORT, gpio_init_structure.Pin); + + /* LCD_TE GPIO deactivation */ + gpio_init_structure.Pin = LCD_TE_PIN; + HAL_GPIO_DeInit(LCD_TE_GPIO_PORT, gpio_init_structure.Pin); + + /* LCD_BL_CTRL GPIO deactivation */ + gpio_init_structure.Pin = LCD_BL_CTRL_PIN; + HAL_GPIO_DeInit(LCD_BL_CTRL_GPIO_PORT, gpio_init_structure.Pin); + + /* GPIO pins clock can be shut down in the application + by surcharging this __weak function */ +} + +/****************************************************************************** + Static Functions +*******************************************************************************/ + +/** + * @brief Draws a character on LCD. + * @param Xpos: Line where to display the character shape + * @param Ypos: Start column address + * @param c: Pointer to the character data + * @retval None + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c) +{ + uint32_t i = 0, j = 0; + uint16_t height, width; + uint8_t offset; + uint8_t *pchar; + uint32_t line; + + height = DrawProp.pFont->Height; + width = DrawProp.pFont->Width; + + offset = 8 *((width + 7)/8) - width ; + + for(i = 0; i < height; i++) + { + pchar = ((uint8_t *)c + (width + 7)/8 * i); + + switch(((width + 7)/8)) + { + case 1: + line = pchar[0]; + break; + + case 2: + line = (pchar[0]<< 8) | pchar[1]; + break; + + case 3: + default: + line = (pchar[0]<< 16) | (pchar[1]<< 8) | pchar[2]; + break; + } + + for (j = 0; j < width; j++) + { + if(line & (1 << (width- j + offset- 1))) + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp.TextColor); + } + else + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp.BackColor); + } + } + Ypos++; + } +} + +/** + * @brief Sets display window. + * @param Xpos: LCD X position + * @param Ypos: LCD Y position + * @param Width: LCD window width + * @param Height: LCD window height + * @retval None + */ +static void SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + if(LcdDrv->SetDisplayWindow != NULL) + { + LcdDrv->SetDisplayWindow(Xpos, Ypos, Width, Height); + } +} + +/** + * @brief Fills a triangle (between 3 points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @param x3: Point 3 X position + * @param y3: Point 3 Y position + * @retval None + */ +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + numadd = deltay; + numpixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + numadd = deltax; + numpixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= numpixels; curpixel++) + { + BSP_LCD_DrawLine(x, y, x3, y3); + + num += numadd; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_lcd.h b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_lcd.h new file mode 100644 index 00000000..d2ed8457 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_lcd.h @@ -0,0 +1,233 @@ +/** + ****************************************************************************** + * @file stm32f723e_discovery_lcd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f723e_discovery_lcd.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F723E_DISCOVERY_LCD_H +#define __STM32F723E_DISCOVERY_LCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f723e_discovery.h" +#include "../Components/st7789h2/st7789h2.h" +#include "../../../Utilities/Fonts/fonts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_LCD STM32F723E-DISCOVERY LCD + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_LCD_Exported_Types STM32F723E DISCOVERY LCD Exported Types + * @{ + */ +typedef struct +{ + uint32_t TextColor; + uint32_t BackColor; + sFONT *pFont; +}LCD_DrawPropTypeDef; +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LCD_Exported_Constants STM32F723E DISCOVERY LCD Exported Constants + * @{ + */ +/** + * @brief LCD status structure definition + */ +#define LCD_OK ((uint8_t)0x00) +#define LCD_ERROR ((uint8_t)0x01) +#define LCD_TIMEOUT ((uint8_t)0x02) + +typedef struct +{ + int16_t X; + int16_t Y; +}Point, * pPoint; + +/** + * @brief Line mode structures definition + */ +typedef enum +{ + CENTER_MODE = 0x01, /* Center mode */ + RIGHT_MODE = 0x02, /* Right mode */ + LEFT_MODE = 0x03 /* Left mode */ +}Line_ModeTypdef; + + +#define LCD_ORIENTATION_PORTRAIT ((uint8_t)0x00) /*!< Portrait orientation choice of LCD screen */ +#define LCD_ORIENTATION_LANDSCAPE ((uint8_t)0x01) /*!< Landscape orientation choice of LCD screen */ +#define LCD_ORIENTATION_LANDSCAPE_ROT180 ((uint32_t)0x02) /*!< Landscape rotated 180° orientation choice of LCD screen */ + + +/** + * @brief LCD color + */ +#define LCD_COLOR_BLUE ((uint16_t)0x001F) +#define LCD_COLOR_GREEN ((uint16_t)0x07E0) +#define LCD_COLOR_RED ((uint16_t)0xF800) +#define LCD_COLOR_CYAN ((uint16_t)0x07FF) +#define LCD_COLOR_MAGENTA ((uint16_t)0xF81F) +#define LCD_COLOR_YELLOW ((uint16_t)0xFFE0) +#define LCD_COLOR_LIGHTBLUE ((uint16_t)0x841F) +#define LCD_COLOR_LIGHTGREEN ((uint16_t)0x87F0) +#define LCD_COLOR_LIGHTRED ((uint16_t)0xFC10) +#define LCD_COLOR_LIGHTMAGENTA ((uint16_t)0xFC1F) +#define LCD_COLOR_LIGHTYELLOW ((uint16_t)0xFFF0) +#define LCD_COLOR_DARKBLUE ((uint16_t)0x0010) +#define LCD_COLOR_DARKGREEN ((uint16_t)0x0400) +#define LCD_COLOR_DARKRED ((uint16_t)0x8000) +#define LCD_COLOR_DARKCYAN ((uint16_t)0x0410) +#define LCD_COLOR_DARKMAGENTA ((uint16_t)0x8010) +#define LCD_COLOR_DARKYELLOW ((uint16_t)0x8400) +#define LCD_COLOR_WHITE ((uint16_t)0xFFFF) +#define LCD_COLOR_LIGHTGRAY ((uint16_t)0xD69A) +#define LCD_COLOR_GRAY ((uint16_t)0x8410) +#define LCD_COLOR_DARKGRAY ((uint16_t)0x4208) +#define LCD_COLOR_BLACK ((uint16_t)0x0000) +#define LCD_COLOR_BROWN ((uint16_t)0xA145) +#define LCD_COLOR_ORANGE ((uint16_t)0xFD20) + +/** + * @brief LCD default font + */ +#define LCD_DEFAULT_FONT Font12 + +/** + * @brief LCD special pins + */ +/* LCD reset pin */ +#define LCD_RESET_PIN GPIO_PIN_7 +#define LCD_RESET_GPIO_PORT GPIOH +#define LCD_RESET_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() +#define LCD_RESET_GPIO_CLK_DISABLE() __HAL_RCC_GPIOH_CLK_DISABLE() + +/* LCD tearing effect pin */ +#define LCD_TE_PIN GPIO_PIN_8 +#define LCD_TE_GPIO_PORT GPIOC +#define LCD_TE_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define LCD_TE_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE() + +/* Backlight control pin */ +#define LCD_BL_CTRL_PIN GPIO_PIN_11 +#define LCD_BL_CTRL_GPIO_PORT GPIOH +#define LCD_BL_CTRL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() +#define LCD_BL_CTRL_GPIO_CLK_DISABLE() __HAL_RCC_GPIOH_CLK_DISABLE() + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_LCD_Exported_Functions STM32F723E DISCOVERY LCD Exported Functions + * @{ + */ +uint8_t BSP_LCD_Init(void); +uint8_t BSP_LCD_InitEx(uint32_t orientation); +uint8_t BSP_LCD_DeInit(void); +uint32_t BSP_LCD_GetXSize(void); +uint32_t BSP_LCD_GetYSize(void); + +uint16_t BSP_LCD_GetTextColor(void); +uint16_t BSP_LCD_GetBackColor(void); +void BSP_LCD_SetTextColor(__IO uint16_t Color); +void BSP_LCD_SetBackColor(__IO uint16_t Color); +void BSP_LCD_SetFont(sFONT *fonts); +sFONT *BSP_LCD_GetFont(void); + +void BSP_LCD_Clear(uint16_t Color); +void BSP_LCD_ClearStringLine(uint16_t Line); +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr); +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Line_ModeTypdef Mode); +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii); + +uint16_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos); +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGB_Code); +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius); +void BSP_LCD_DrawBitmap(uint16_t Xpos, uint16_t Ypos, uint8_t *pbmp); +void BSP_LCD_DrawRGBImage(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint16_t Ysize, uint8_t *pbmp); +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius); + +void BSP_LCD_DisplayOff(void); +void BSP_LCD_DisplayOn(void); + +/* These functions can be modified in case the current settings + need to be changed for specific application needs */ +__weak void BSP_LCD_MspInit(void); +__weak void BSP_LCD_MspDeInit(void); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F723E_DISCOVERY_LCD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_psram.c b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_psram.c new file mode 100644 index 00000000..3a365dfc --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_psram.c @@ -0,0 +1,403 @@ +/** + ****************************************************************************** + * @file stm32f723e_discovery_psram.c + * @author MCD Application Team + * @brief This file includes the PSRAM driver for the IS61WV51216BLL-10MLI memory + * device mounted on STM32F723E-DISCOVERY boards. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the IS61WV51216BLL-10M PSRAM external memory mounted + on STM32F723E discovery board. + - This driver does not need a specific component driver for the PSRAM device + to be included with. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the PSRAM external memory using the BSP_PSRAM_Init() function. This + function includes the MSP layer hardware resources initialization and the + FMC controller configuration to interface with the external PSRAM memory. + + + PSRAM read/write operations + o PSRAM external memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_PSRAM_ReadData()/BSP_PSRAM_WriteData(), or by DMA transfer using the functions + BSP_PSRAM_ReadData_DMA()/BSP_PSRAM_WriteData_DMA(). + o The AHB access is performed with 16-bit width transaction, the DMA transfer + configuration is fixed at single (no burst) halfword transfer + (see the PSRAM_MspInit() static function). + o User can implement his own functions for read/write access with his desired + configurations. + o If interrupt mode is used for DMA transfer, the function BSP_PSRAM_DMA_IRQHandler() + is called in IRQ handler file, to serve the generated interrupt once the DMA + transfer is complete. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_sram.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f723e_discovery_psram.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_PSRAM STM32F723E-DISCOVERY PSRAM + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_PSRAM_Private_Types_Definitions PSRAM Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_PSRAM_Private_Defines PSRAM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_PSRAM_Private_Macros PSRAM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_PSRAM_Private_Variables PSRAM Private Variables + * @{ + */ +SRAM_HandleTypeDef psramHandle; + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_PSRAM_Private_Function_Prototypes PSRAM Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_PSRAM_Private_Functions PSRAM Private Functions + * @{ + */ + +/** + * @brief Initializes the PSRAM device. + * @retval PSRAM status + */ +uint8_t BSP_PSRAM_Init(void) +{ + static FMC_NORSRAM_TimingTypeDef Timing; + static uint8_t psram_status = PSRAM_ERROR; + + /* PSRAM device configuration */ + psramHandle.Instance = FMC_NORSRAM_DEVICE; + psramHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + /* PSRAM device configuration */ + /* Timing configuration derived from system clock (up to 216Mhz) + for 108Mhz as PSRAM clock frequency */ + Timing.AddressSetupTime = 9; + Timing.AddressHoldTime = 2; + Timing.DataSetupTime = 6; + Timing.BusTurnAroundDuration = 1; + Timing.CLKDivision = 2; + Timing.DataLatency = 2; + Timing.AccessMode = FMC_ACCESS_MODE_A; + + psramHandle.Init.NSBank = FMC_NORSRAM_BANK1; + psramHandle.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; + psramHandle.Init.MemoryType = FMC_MEMORY_TYPE_SRAM; + psramHandle.Init.MemoryDataWidth = PSRAM_MEMORY_WIDTH; + psramHandle.Init.BurstAccessMode = PSRAM_BURSTACCESS; + psramHandle.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; + psramHandle.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; + psramHandle.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; + psramHandle.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE; + psramHandle.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; + psramHandle.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE; + psramHandle.Init.WriteBurst = PSRAM_WRITEBURST; + psramHandle.Init.WriteFifo = FMC_WRITE_FIFO_DISABLE; + psramHandle.Init.PageSize = FMC_PAGE_SIZE_NONE; + psramHandle.Init.ContinuousClock = CONTINUOUSCLOCK_FEATURE; + + /* PSRAM controller initialization */ + BSP_PSRAM_MspInit(&psramHandle, NULL); /* __weak function can be rewritten by the application */ + if(HAL_SRAM_Init(&psramHandle, &Timing, &Timing) != HAL_OK) + { + psram_status = PSRAM_ERROR; + } + else + { + psram_status = PSRAM_OK; + } + return psram_status; +} + +/** + * @brief DeInitializes the PSRAM device. + * @retval PSRAM status + */ +uint8_t BSP_PSRAM_DeInit(void) +{ + static uint8_t psram_status = PSRAM_ERROR; + /* PSRAM device de-initialization */ + psramHandle.Instance = FMC_NORSRAM_DEVICE; + psramHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + if(HAL_SRAM_DeInit(&psramHandle) != HAL_OK) + { + psram_status = PSRAM_ERROR; + } + else + { + psram_status = PSRAM_OK; + } + + /* PSRAM controller de-initialization */ + BSP_PSRAM_MspDeInit(&psramHandle, NULL); + + return psram_status; +} + +/** + * @brief Reads an amount of data from the PSRAM device in polling mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval PSRAM status + */ +uint8_t BSP_PSRAM_ReadData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Read_16b(&psramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return PSRAM_ERROR; + } + else + { + return PSRAM_OK; + } +} + +/** + * @brief Reads an amount of data from the PSRAM device in DMA mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval PSRAM status + */ +uint8_t BSP_PSRAM_ReadData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Read_DMA(&psramHandle, (uint32_t *)uwStartAddress, (uint32_t *)pData, uwDataSize) != HAL_OK) + { + return PSRAM_ERROR; + } + else + { + return PSRAM_OK; + } +} + +/** + * @brief Writes an amount of data from the PSRAM device in polling mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval PSRAM status + */ +uint8_t BSP_PSRAM_WriteData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Write_16b(&psramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return PSRAM_ERROR; + } + else + { + return PSRAM_OK; + } +} + +/** + * @brief Writes an amount of data from the PSRAM device in DMA mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval PSRAM status + */ +uint8_t BSP_PSRAM_WriteData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Write_DMA(&psramHandle, (uint32_t *)uwStartAddress, (uint32_t *)pData, uwDataSize) != HAL_OK) + { + return PSRAM_ERROR; + } + else + { + return PSRAM_OK; + } +} + +/** + * @brief Initializes PSRAM MSP. + * @param hsram: PSRAM handle + * @param Params + * @retval None + */ +__weak void BSP_PSRAM_MspInit(SRAM_HandleTypeDef *hsram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable FMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + + /* Enable chosen DMAx clock */ + __PSRAM_DMAx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF12_FMC; + + /* GPIOD configuration: GPIO_PIN_7 is FMC_NE1 , GPIO_PIN_11 ans GPIO_PIN_12 are PSRAM_A16 and PSRAM_A17 */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7 | GPIO_PIN_8 |\ + GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_14 | GPIO_PIN_15; + + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOE configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 |\ + GPIO_PIN_12 |GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOF configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOF, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + /* Configure common DMA parameters */ + dma_handle.Init.Channel = PSRAM_DMAx_CHANNEL; + dma_handle.Init.Direction = DMA_MEMORY_TO_MEMORY; + dma_handle.Init.PeriphInc = DMA_PINC_ENABLE; + dma_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + dma_handle.Init.Mode = DMA_NORMAL; + dma_handle.Init.Priority = DMA_PRIORITY_HIGH; + dma_handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + dma_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_handle.Init.MemBurst = DMA_MBURST_SINGLE; + dma_handle.Init.PeriphBurst = DMA_PBURST_SINGLE; + + dma_handle.Instance = PSRAM_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsram, hdma, dma_handle); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&dma_handle); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&dma_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(PSRAM_DMAx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(PSRAM_DMAx_IRQn); +} + + +/** + * @brief DeInitializes SRAM MSP. + * @param hsram: SRAM handle + * @param Params + * @retval None + */ +__weak void BSP_PSRAM_MspDeInit(SRAM_HandleTypeDef *hsram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + + /* Disable NVIC configuration for DMA interrupt */ + HAL_NVIC_DisableIRQ(PSRAM_DMAx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_handle.Instance = PSRAM_DMAx_STREAM; + HAL_DMA_DeInit(&dma_handle); + + /* GPIO pins clock, FMC clock and DMA clock can be shut down in the applications + by surcharging this __weak function */ +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_psram.h b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_psram.h new file mode 100644 index 00000000..0018f6c4 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_psram.h @@ -0,0 +1,140 @@ +/** + ****************************************************************************** + * @file stm32f723e_discovery_psram.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f723e_discovery_psram.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F723E_DISCOVERY_PSRAM_H +#define __STM32F723E_DISCOVERY_PSRAM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY_PSRAM + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_PSRAM_Exported_Types PSRAM Exported Types + * @{ + */ + +/** + * @brief PSRAM status structure definition + */ +#define PSRAM_OK ((uint8_t)0x00) +#define PSRAM_ERROR ((uint8_t)0x01) + +#define PSRAM_DEVICE_ADDR ((uint32_t)0x60000000) +#define PSRAM_DEVICE_SIZE ((uint32_t)0x80000) /* SRAM device size in Bytes */ + +/* #define SRAM_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_8*/ +#define PSRAM_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_16 + +#define PSRAM_BURSTACCESS FMC_BURST_ACCESS_MODE_DISABLE +/* #define PSRAM_BURSTACCESS FMC_BURST_ACCESS_MODE_ENABLE*/ + +#define PSRAM_WRITEBURST FMC_WRITE_BURST_DISABLE +/* #define PSRAM_WRITEBURST FMC_WRITE_BURST_ENABLE */ + +#define CONTINUOUSCLOCK_FEATURE FMC_CONTINUOUS_CLOCK_SYNC_ONLY +/* #define CONTINUOUSCLOCK_FEATURE FMC_CONTINUOUS_CLOCK_SYNC_ASYNC */ + +/* DMA definitions for SRAM DMA transfer */ +#define __PSRAM_DMAx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define __PSRAM_DMAx_CLK_DISABLE __HAL_RCC_DMA2_CLK_DISABLE +#define PSRAM_DMAx_CHANNEL DMA_CHANNEL_0 +#define PSRAM_DMAx_STREAM DMA2_Stream5 +#define PSRAM_DMAx_IRQn DMA2_Stream5_IRQn +#define BSP_PSRAM_DMA_IRQHandler DMA2_Stream5_IRQHandler + +/** @defgroup STM32F723E_DISCOVERY_PSRAM_Exported_Macro PSRAM Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_PSRAM_Exported_Functions PSRAM Exported Functions + * @{ + */ +uint8_t BSP_PSRAM_Init(void); +uint8_t BSP_PSRAM_DeInit(void); +uint8_t BSP_PSRAM_ReadData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_PSRAM_ReadData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_PSRAM_WriteData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_PSRAM_WriteData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_PSRAM_MspInit(SRAM_HandleTypeDef *hsram, void *Params); +void BSP_PSRAM_MspDeInit(SRAM_HandleTypeDef *hsram, void *Params); +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F723E_DISCOVERY_PSRAM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_qspi.c b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_qspi.c new file mode 100644 index 00000000..759e3b3c --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_qspi.c @@ -0,0 +1,1182 @@ +/** + ****************************************************************************** + * @file stm32f723e_discovery_qspi.c + * @author MCD Application Team + * @brief This file includes a standard driver for the MX25L512 QSPI + * memory mounted on STM32F723E-Discovery board. + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + (#) This driver is used to drive the MX25L512 QSPI external + memory mounted on STM32F723E-Discovery board. + + (#) This driver need a specific component driver (MX25L51245G) to be included with. + + (#) Initialization steps: + (++) Initialize the QPSI external memory using the BSP_QSPI_Init() function. This + function includes the MSP layer hardware resources initialization and the + QSPI interface with the external memory. + + (#) QSPI memory operations + (++) QSPI memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_QSPI_Read()/BSP_QSPI_Write(). + (++) The function BSP_QSPI_GetInfo() returns the configuration of the QSPI memory. + (see the QSPI memory data sheet) + (++) Perform erase block operation using the function BSP_QSPI_Erase_Block() and by + specifying the block address. You can perform an erase operation of the whole + chip by calling the function BSP_QSPI_Erase_Chip(). + (++) The function BSP_QSPI_GetStatus() returns the current status of the QSPI memory. + (see the QSPI memory data sheet) + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_qspi.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- mx25l512.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f723e_discovery_qspi.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_QSPI STM32F723E-DISCOVERY QSPI + * @{ + */ + + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup STM32F723E_DISCOVERY_QSPI_Private_Variables STM32F723E_DISCOVERY QSPI Private Variables + * @{ + */ +QSPI_HandleTypeDef QSPIHandle; + +/** + * @} + */ + + + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup STM32F723E_DISCOVERY_QSPI_Private_Functions STM32F723E_DISCOVERY QSPI Private Functions + * @{ + */ +static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_EnterMemory_QPI(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_ExitMemory_QPI(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_OutDrvStrengthCfg(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_AutoPollingMemReady (QSPI_HandleTypeDef *hqspi, uint32_t Timeout); + +/** + * @} + */ + +/** @defgroup STM32F723E_DISCOVERY_QSPI_Exported_Functions STM32F723E_DISCOVERY QSPI Exported Functions + * @{ + */ + +/** + * @brief Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Init(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level initialization */ + BSP_QSPI_MspInit(&QSPIHandle, NULL); + + /* QSPI initialization */ + /* QSPI freq = SYSCLK /(1 + ClockPrescaler) = 216 MHz/(1+1) = 108 Mhz */ + QSPIHandle.Init.ClockPrescaler = 1; /* QSPI freq = 216 MHz/(1+1) = 108 Mhz */ + QSPIHandle.Init.FifoThreshold = 16; + QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; + QSPIHandle.Init.FlashSize = POSITION_VAL(MX25L512_FLASH_SIZE) - 1; + QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_4_CYCLE; /* Min 30ns for nonRead */ + QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; + QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1; + QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE; + + if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* QSPI memory reset */ + if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Put QSPI memory in QPI mode */ + if( QSPI_EnterMemory_QPI( &QSPIHandle )!=QSPI_OK ) + { + return QSPI_NOT_SUPPORTED; + } + + /* Set the QSPI memory in 4-bytes address mode */ + if (QSPI_EnterFourBytesAddress(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Configuration of the dummy cycles on QSPI memory side */ + if (QSPI_DummyCyclesCfg(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Configuration of the Output driver strength on memory side */ + if( QSPI_OutDrvStrengthCfg( &QSPIHandle ) != QSPI_OK ) + { + return QSPI_NOT_SUPPORTED; + } + + return QSPI_OK; +} + +/** + * @brief De-Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_DeInit(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Put QSPI memory in SPI mode */ + if( QSPI_ExitMemory_QPI(&QSPIHandle )!=QSPI_OK ) + { + return QSPI_NOT_SUPPORTED; + } + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level De-initialization */ + BSP_QSPI_MspDeInit(&QSPIHandle, NULL); + + return QSPI_OK; +} + +/** + * @brief Reads an amount of data from the QSPI memory. + * @param pData: Pointer to data to be read + * @param ReadAddr: Read start address + * @param Size: Size of data to read + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the read command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = QSPI_READ_4_BYTE_ADDR_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.Address = ReadAddr; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = MX25L512_DUMMY_CYCLES_READ_QUAD_IO; + s_command.NbData = Size; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Set S# timing for Read command */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_1_CYCLE); + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Restore S# timing for nonRead commands */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_4_CYCLE); + + return QSPI_OK; +} + +/** + * @brief Writes an amount of data to the QSPI memory. + * @param pData: Pointer to data to be written + * @param WriteAddr: Write start address + * @param Size: Size of data to write + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + uint32_t end_addr, current_size, current_addr; + + /* Calculation of the size between the write address and the end of the page */ + current_size = MX25L512_PAGE_SIZE - (WriteAddr % MX25L512_PAGE_SIZE); + + /* Check if the size of the data is less than the remaining place in the page */ + if (current_size > Size) + { + current_size = Size; + } + + /* Initialize the address variables */ + current_addr = WriteAddr; + end_addr = WriteAddr + Size; + + /* Initialize the program command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = QSPI_PAGE_PROG_4_BYTE_ADDR_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Perform the write page by page */ + do + { + s_command.Address = current_addr; + s_command.NbData = current_size; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of program */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update the address and size variables for next page programming */ + current_addr += current_size; + pData += current_size; + current_size = ((current_addr + MX25L512_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : MX25L512_PAGE_SIZE; + } while (current_addr < end_addr); + + return QSPI_OK; +} + +/** + * @brief Erases the specified block of the QSPI memory. + * @param BlockAddress: Block address to erase + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = SUBSECTOR_ERASE_4_BYTE_ADDR_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.Address = BlockAddress; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, MX25L512_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Erases the entire QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Chip(void) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = BULK_ERASE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, MX25L512_BULK_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Reads current status of the QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetStatus(void) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg; + + /* Initialize the read flag status register command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Check the value of the register*/ + if ((reg & MX25L512_SR_WIP) == 0) + { + return QSPI_OK; + } + else + { + return QSPI_BUSY; + } +} + +/** + * @brief Return the configuration of the QSPI memory. + * @param pInfo: pointer on the configuration structure + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetInfo(QSPI_Info* pInfo) +{ + /* Configure the structure with the memory configuration */ + pInfo->FlashSize = MX25L512_FLASH_SIZE; + pInfo->EraseSectorSize = MX25L512_SUBSECTOR_SIZE; + pInfo->EraseSectorsNumber = (MX25L512_FLASH_SIZE/MX25L512_SUBSECTOR_SIZE); + pInfo->ProgPageSize = MX25L512_PAGE_SIZE; + pInfo->ProgPagesNumber = (MX25L512_FLASH_SIZE/MX25L512_PAGE_SIZE); + + return QSPI_OK; +} + +/** + * @brief Configure the QSPI in memory-mapped mode + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_EnableMemoryMappedMode(void) +{ + QSPI_CommandTypeDef s_command; + QSPI_MemoryMappedTypeDef s_mem_mapped_cfg; + + /* Configure the command for the read instruction */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = QSPI_READ_4_BYTE_ADDR_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = MX25L512_DUMMY_CYCLES_READ_QUAD_IO; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the memory mapped mode */ + s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; + s_mem_mapped_cfg.TimeOutPeriod = 0; + + if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @} + */ + +/** @addtogroup STM32F723E_DISCOVERY_QSPI_Private_Functions + * @{ + */ + +/** + * @brief QSPI MSP Initialization + * This function configures the hardware resources used in this example: + * - Peripheral's clock enable + * - Peripheral's GPIO Configuration + * - NVIC configuration for QSPI interrupt + * @retval None + */ +__weak void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /*##-1- Enable peripherals and GPIO Clocks #################################*/ + /* Enable the QuadSPI memory interface clock */ + QSPI_CLK_ENABLE(); + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + /* Enable GPIO clocks */ + QSPI_CS_GPIO_CLK_ENABLE(); + QSPI_CLK_GPIO_CLK_ENABLE(); + QSPI_D0_GPIO_CLK_ENABLE(); + QSPI_D1_GPIO_CLK_ENABLE(); + QSPI_D2_GPIO_CLK_ENABLE(); + QSPI_D3_GPIO_CLK_ENABLE(); + + /*##-2- Configure peripheral GPIO ##########################################*/ + /* QSPI CS GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CS_PIN; + gpio_init_structure.Alternate = QSPI_CS_PIN_AF; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &gpio_init_structure); + /* QSPI CLK GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CLK_PIN; + gpio_init_structure.Alternate = QSPI_CLK_PIN_AF; + gpio_init_structure.Pull = GPIO_NOPULL; + HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &gpio_init_structure); + /* QSPI D0 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D0_PIN; + gpio_init_structure.Alternate = QSPI_D0_PIN_AF; + HAL_GPIO_Init(QSPI_D0_GPIO_PORT, &gpio_init_structure); + /* QSPI D1 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D1_PIN; + gpio_init_structure.Alternate = QSPI_D1_PIN_AF; + HAL_GPIO_Init(QSPI_D1_GPIO_PORT, &gpio_init_structure); + /* QSPI D2 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D2_PIN; + gpio_init_structure.Alternate = QSPI_D2_PIN_AF; + HAL_GPIO_Init(QSPI_D2_GPIO_PORT, &gpio_init_structure); + /* QSPI D3 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D3_PIN; + gpio_init_structure.Alternate = QSPI_D3_PIN_AF; + HAL_GPIO_Init(QSPI_D3_GPIO_PORT, &gpio_init_structure); + + /*##-3- Configure the NVIC for QSPI #########################################*/ + /* NVIC configuration for QSPI interrupt */ + HAL_NVIC_SetPriority(QUADSPI_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(QUADSPI_IRQn); +} + +/** + * @brief QSPI MSP De-Initialization + * This function frees the hardware resources used in this example: + * - Disable the Peripheral's clock + * - Revert GPIO and NVIC configuration to their default state + * @retval None + */ +__weak void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + /*##-1- Disable the NVIC for QSPI ###########################################*/ + HAL_NVIC_DisableIRQ(QUADSPI_IRQn); + + /*##-2- Disable peripherals and GPIO Clocks ################################*/ + /* De-Configure QSPI pins */ + HAL_GPIO_DeInit(QSPI_CS_GPIO_PORT, QSPI_CS_PIN); + HAL_GPIO_DeInit(QSPI_CLK_GPIO_PORT, QSPI_CLK_PIN); + HAL_GPIO_DeInit(QSPI_D0_GPIO_PORT, QSPI_D0_PIN); + HAL_GPIO_DeInit(QSPI_D1_GPIO_PORT, QSPI_D1_PIN); + HAL_GPIO_DeInit(QSPI_D2_GPIO_PORT, QSPI_D2_PIN); + HAL_GPIO_DeInit(QSPI_D3_GPIO_PORT, QSPI_D3_PIN); + + /*##-3- Reset peripherals ##################################################*/ + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + + /* Disable the QuadSPI memory interface clock */ + QSPI_CLK_DISABLE(); +} + +/** + * @brief This function reset the QSPI memory. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + uint8_t reg; + + /* Send command RESET command in QPI mode (QUAD I/Os) */ + /* Initialize the reset enable command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = RESET_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + /* Send the reset memory command */ + s_command.Instruction = RESET_MEMORY_CMD; + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Send command RESET command in SPI mode */ + /* Initialize the reset enable command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = RESET_ENABLE_CMD; + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + /* Send the reset memory command */ + s_command.Instruction = RESET_MEMORY_CMD; + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* After reset CMD, 1000ms requested if QSPI memory SWReset occured during full chip erase operation */ + HAL_Delay( 1000 ); + + /* Configure automatic polling mode to wait the WIP bit=0 */ + s_config.Match = 0; + s_config.Mask = MX25L512_SR_WIP; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_1_LINE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Initialize the reading of status register */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations, command in 1 bit */ + /* Enable write operations */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = WRITE_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for write enabling */ + s_config.Match = MX25L512_SR_WREN; + s_config.Mask = MX25L512_SR_WREN; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_1_LINE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Update the configuration register with new dummy cycles */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = WRITE_STATUS_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable the Quad IO on the QSPI memory (Non-volatile bit) */ + reg |= MX25L512_SR_QUADEN; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* 40ms Write Status/Configuration Register Cycle Time */ + HAL_Delay( 40 ); + + return QSPI_OK; +} + +/** + * @brief This function set the QSPI memory in 4-byte address mode + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = ENTER_4_BYTE_ADDR_MODE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(hqspi) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait the memory is ready */ + if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function configure the dummy cycles on memory side. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg[2]; + + /* Initialize the reading of status register */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Initialize the reading of configuration register */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, &(reg[1]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations */ + if (QSPI_WriteEnable(hqspi) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update the configuration register with new dummy cycles */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = WRITE_STATUS_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 2; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* MX25L512_DUMMY_CYCLES_READ_QUAD = 3 for 10 cycles in QPI mode */ + MODIFY_REG( reg[1], MX25L512_CR_NB_DUMMY, (MX25L512_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(MX25L512_CR_NB_DUMMY))); + + /* Configure the write volatile configuration register command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(hqspi, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* 40ms Write Status/Configuration Register Cycle Time */ + HAL_Delay( 40 ); + + return QSPI_OK; +} + +/** + * @brief This function put QSPI memory in QPI mode (quad I/O). + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_EnterMemory_QPI( QSPI_HandleTypeDef *hqspi ) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Initialize the QPI enable command */ + /* QSPI memory is supported to be in SPI mode, so CMD on 1 LINE */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = ENTER_QUAD_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait the QUADEN bit=1 and WIP bit=0 */ + s_config.Match = MX25L512_SR_QUADEN; + s_config.Mask = MX25L512_SR_QUADEN|MX25L512_SR_WIP; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_4_LINES; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function put QSPI memory in SPI mode. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_ExitMemory_QPI( QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the QPI enable command */ + /* QSPI memory is supported to be in QPI mode, so CMD on 4 LINES */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = EXIT_QUAD_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function configure the Output driver strength on memory side. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_OutDrvStrengthCfg( QSPI_HandleTypeDef *hqspi ) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg[2]; + + /* Initialize the reading of status register */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Initialize the reading of configuration register */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, &(reg[1]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update the configuration register with new output driver strength */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = WRITE_STATUS_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 2; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Set Output Strength of the QSPI memory 15 ohms */ + MODIFY_REG( reg[1], MX25L512_CR_ODS, (MX25L512_CR_ODS_15 << POSITION_VAL(MX25L512_CR_ODS))); + + /* Configure the write volatile configuration register command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(hqspi, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function send a Write Enable and wait it is effective. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Enable write operations */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = WRITE_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for write enabling */ + s_config.Match = MX25L512_SR_WREN; + s_config.Mask = MX25L512_SR_WREN; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_4_LINES; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function read the SR of the memory and wait the EOP. + * @param hqspi: QSPI handle + * @param Timeout + * @retval None + */ +static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Configure automatic polling mode to wait for memory ready */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + s_config.Match = 0; + s_config.Mask = MX25L512_SR_WIP; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, Timeout) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_qspi.h b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_qspi.h new file mode 100644 index 00000000..34f5da5b --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_qspi.h @@ -0,0 +1,175 @@ +/** + ****************************************************************************** + * @file stm32f723e_discovery_qspi.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f723e_discovery_qspi.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY + * @{ + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F723E_DISCOVERY_QSPI_H +#define __STM32F723E_DISCOVERY_QSPI_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" +#include "../Components/mx25l512/mx25l512.h" + +/** @addtogroup STM32F723E_DISCOVERY_QSPI + * @{ + */ + + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup STM32F723E_DISCOVERY_QSPI_Exported_Constants STM32F723E_DISCOVERY_QSPI Exported Constants + * @{ + */ +/* QSPI Error codes */ +#define QSPI_OK ((uint8_t)0x00) +#define QSPI_ERROR ((uint8_t)0x01) +#define QSPI_BUSY ((uint8_t)0x02) +#define QSPI_NOT_SUPPORTED ((uint8_t)0x04) +#define QSPI_SUSPENDED ((uint8_t)0x08) + + +/* Definition for QSPI clock resources */ +#define QSPI_CLK_ENABLE() __HAL_RCC_QSPI_CLK_ENABLE() +#define QSPI_CLK_DISABLE() __HAL_RCC_QSPI_CLK_DISABLE() +#define QSPI_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_CLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_D0_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define QSPI_D1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define QSPI_D2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() +#define QSPI_D3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() + +#define QSPI_FORCE_RESET() __HAL_RCC_QSPI_FORCE_RESET() +#define QSPI_RELEASE_RESET() __HAL_RCC_QSPI_RELEASE_RESET() + +/* Definition for QSPI Pins */ +/* QSPI_CS */ +#define QSPI_CS_PIN GPIO_PIN_6 +#define QSPI_CS_GPIO_PORT GPIOB +#define QSPI_CS_PIN_AF GPIO_AF10_QUADSPI +/* QSPI_CLK */ +#define QSPI_CLK_PIN GPIO_PIN_2 +#define QSPI_CLK_GPIO_PORT GPIOB +#define QSPI_CLK_PIN_AF GPIO_AF9_QUADSPI +/* QSPI_D0 */ +#define QSPI_D0_PIN GPIO_PIN_9 +#define QSPI_D0_GPIO_PORT GPIOC +#define QSPI_D0_PIN_AF GPIO_AF9_QUADSPI +/* QSPI_D1 */ +#define QSPI_D1_PIN GPIO_PIN_10 +#define QSPI_D1_GPIO_PORT GPIOC +#define QSPI_D1_PIN_AF GPIO_AF9_QUADSPI +/* QSPI_D2 */ +#define QSPI_D2_PIN GPIO_PIN_2 +#define QSPI_D2_GPIO_PORT GPIOE +#define QSPI_D2_PIN_AF GPIO_AF9_QUADSPI +/* QSPI_D3 */ +#define QSPI_D3_PIN GPIO_PIN_13 +#define QSPI_D3_GPIO_PORT GPIOD +#define QSPI_D3_PIN_AF GPIO_AF9_QUADSPI + +/** + * @} + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup STM32F723E_DISCOVERY_QSPI_Exported_Types STM32F723E_DISCOVERY_QSPI Exported Types + * @{ + */ +/* QSPI Info */ +typedef struct { + uint32_t FlashSize; /*!< Size of the flash */ + uint32_t EraseSectorSize; /*!< Size of sectors for the erase operation */ + uint32_t EraseSectorsNumber; /*!< Number of sectors for the erase operation */ + uint32_t ProgPageSize; /*!< Size of pages for the program operation */ + uint32_t ProgPagesNumber; /*!< Number of pages for the program operation */ +} QSPI_Info; + +/** + * @} + */ + + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup STM32F723E_DISCOVERY_QSPI_Exported_Functions + * @{ + */ +uint8_t BSP_QSPI_Init (void); +uint8_t BSP_QSPI_DeInit (void); +uint8_t BSP_QSPI_Read (uint8_t* pData, uint32_t ReadAddr, uint32_t Size); +uint8_t BSP_QSPI_Write (uint8_t* pData, uint32_t WriteAddr, uint32_t Size); +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress); +uint8_t BSP_QSPI_Erase_Chip (void); +uint8_t BSP_QSPI_GetStatus (void); +uint8_t BSP_QSPI_GetInfo (QSPI_Info* pInfo); +uint8_t BSP_QSPI_EnableMemoryMappedMode(void); + +/* These functions can be modified in case the current settings + need to be changed for specific application needs */ +void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params); +void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F723E_DISCOVERY_QSPI_H */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_ts.c b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_ts.c new file mode 100644 index 00000000..1b2fca63 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_ts.c @@ -0,0 +1,485 @@ +/** + ****************************************************************************** + * @file stm32f723e_discovery_ts.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the Touch + * Screen on STM32F723E-DISCOVERY evaluation board. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* File Info : ----------------------------------------------------------------- + User NOTES +1. How To use this driver: +-------------------------- + - This driver is used to drive the touch screen module of the STM32F723E-DISCOVERY + evaluation board on the FRIDA LCD mounted on MB1260 discovery board. + The touch screen driver IC is a FT6x36 type which share the same register naming + with FT6206 type. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the TS module using the BSP_TS_Init() function. This + function includes the MSP layer hardware resources initialization and the + communication layer configuration to start the TS use. The LCD size properties + (x and y) are passed as parameters. + Note: The FT6x36 requires a calibration. This should be done at application level. + Refer to BSP example to correctly calibrate the touch screen. + o If TS interrupt mode is desired, you must configure the TS interrupt mode + by calling the function BSP_TS_ITConfig(). The TS interrupt mode is generated + as an external interrupt whenever a touch is detected. + + + Touch screen use + o The touch screen state is captured whenever the function BSP_TS_GetState() is + used. This function returns information about the last LCD touch occurred + in the TS_StateTypeDef structure. +------------------------------------------------------------------------------*/ + +/* Dependencies +- stm32f723e_discovery_lcd.c +- ft6x06.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f723e_discovery_ts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY + * @{ + */ + +/** @defgroup STM32F723E_DISCOVERY_TS STM32F723E-DISCOVERY TS + * @{ + */ + +/** @defgroup STM32F723E-DISCOVERY_TS_Private_Types_Definitions TS Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E-DISCOVERY_TS_Private_Defines TS Private Types Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E-DISCOVERY_TS_Private_Macros TS Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E-DISCOVERY_TS_Imported_Variables TS Imported Variables + * @{ + */ + /** + * @} + */ + +/** @defgroup STM32F723E-DISCOVERY_TS_Private_Variables TS Private Variables + * @{ + */ +static TS_DrvTypeDef *tsDriver; +static uint8_t I2C_Address = 0; +static uint8_t tsOrientation = TS_SWAP_NONE; + +/* Table for touchscreen event information display on LCD : table indexed on enum @ref TS_TouchEventTypeDef information */ +char * ts_event_string_tab[TOUCH_EVENT_NB_MAX] = { "None", + "Press down", + "Lift up", + "Contact" + }; + +/* Table for touchscreen gesture Id information display on LCD : table indexed on enum @ref TS_GestureIdTypeDef information */ +char * ts_gesture_id_string_tab[GEST_ID_NB_MAX] = { "None", + "Move Up", + "Move Right", + "Move Down", + "Move Left", + "Zoom In", + "Zoom Out" + }; +/** + * @} + */ + +/** @defgroup STM32F723E-DISCOVERY_TS_Private_Function_Prototypes TS Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F723E-DISCOVERY_TS_Public_Functions TS Public Functions + * @{ + */ +/** + * @brief Initializes and configures the touch screen functionalities and + * configures all necessary hardware resources (GPIOs, I2C, clocks..). + * @param ts_SizeX : Maximum X size of the TS area on LCD + * @param ts_SizeY : Maximum Y size of the TS area on LCD + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY) +{ + return (BSP_TS_InitEx(ts_SizeX, ts_SizeY, TS_ORIENTATION_LANDSCAPE)); +} + +/** + * @brief Initializes and configures the touch screen functionalities and + * configures all necessary hardware resources (GPIOs, I2C, clocks..) + * with a given orientation + * @param ts_SizeX : Maximum X size of the TS area on LCD + * @param ts_SizeY : Maximum Y size of the TS area on LCD + * @param orientation : TS_ORIENTATION_LANDSCAPE or TS_ORIENTATION_PORTRAIT + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_InitEx(uint16_t ts_SizeX, uint16_t ts_SizeY, uint8_t orientation) +{ + uint8_t ts_status = TS_OK; + + /* Note : I2C_Address is un-initialized here, but is not used at all in init function */ + /* but the prototype of Init() is like that in template and should be respected */ + + /* Initialize the communication channel to sensor (I2C) if necessary */ + /* that is initialization is done only once after a power up */ + ft6x06_ts_drv.Init(I2C_Address); + + /* Scan FT6x36 TouchScreen IC controller ID register by I2C Read */ + /* Verify this is a FT6x36, otherwise this is an error case */ + if(ft6x06_ts_drv.ReadID(TS_I2C_ADDRESS) == FT6x36_ID_VALUE) + { + /* Found FT6x36 : Initialize the TS driver structure */ + tsDriver = &ft6x06_ts_drv; + + I2C_Address = TS_I2C_ADDRESS; + + /* Get LCD chosen orientation */ + if(orientation == TS_ORIENTATION_PORTRAIT) + { + tsOrientation = TS_SWAP_X | TS_SWAP_Y; + } + else if(orientation == TS_ORIENTATION_LANDSCAPE_ROT180) + { + tsOrientation = TS_SWAP_XY; + } + else + { + tsOrientation = TS_SWAP_XY | TS_SWAP_Y; + } + + if(ts_status == TS_OK) + { + /* Software reset the TouchScreen */ + tsDriver->Reset(I2C_Address); + + /* Calibrate, Configure and Start the TouchScreen driver */ + tsDriver->Start(I2C_Address); + + } /* of if(ts_status == TS_OK) */ + } + else + { + ts_status = TS_DEVICE_NOT_FOUND; + } + + return (ts_status); +} + +/** + * @brief Configures and enables the touch screen interrupts. + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_ITConfig(void) +{ + uint8_t ts_status = TS_OK; + GPIO_InitTypeDef gpio_init_structure; + + /* Msp Init of GPIO used for TS_INT pin coming from TouchScreen driver IC FT6x36 */ + /* When touchscreen is operated in interrupt mode */ + BSP_TS_INT_MspInit(); + + /* Configure Interrupt mode for TS_INT pin falling edge : when a new touch is available */ + /* TS_INT pin is active on low level on new touch available */ + gpio_init_structure.Pin = TS_INT_PIN; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Mode = GPIO_MODE_IT_FALLING; + HAL_GPIO_Init(TS_INT_GPIO_PORT, &gpio_init_structure); + + /* Enable and set the TS_INT EXTI Interrupt to an intermediate priority */ + HAL_NVIC_SetPriority((IRQn_Type)(TS_INT_EXTI_IRQn), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(TS_INT_EXTI_IRQn)); + + /* Enable the TS in interrupt mode */ + /* In that case the INT output of FT6206 when new touch is available */ + /* is active on low level and directed on EXTI */ + tsDriver->EnableIT(I2C_Address); + + return (ts_status); +} + +/** + * @brief Returns status and positions of the touch screen. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State) +{ + static uint32_t _x[TS_MAX_NB_TOUCH] = {0, 0}; + static uint32_t _y[TS_MAX_NB_TOUCH] = {0, 0}; + uint8_t ts_status = TS_OK; + uint16_t tmp; + uint16_t Raw_x[TS_MAX_NB_TOUCH]; + uint16_t Raw_y[TS_MAX_NB_TOUCH]; + uint16_t xDiff; + uint16_t yDiff; + uint32_t index; +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + uint32_t weight = 0; + uint32_t area = 0; + uint32_t event = 0; +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + /* Check and update the number of touches active detected */ + TS_State->touchDetected = tsDriver->DetectTouch(I2C_Address); + if(TS_State->touchDetected) + { + for(index=0; index < TS_State->touchDetected; index++) + { + /* Get each touch coordinates */ + tsDriver->GetXY(I2C_Address, &(Raw_x[index]), &(Raw_y[index])); + + if(tsOrientation & TS_SWAP_XY) + { + tmp = Raw_x[index]; + Raw_x[index] = Raw_y[index]; + Raw_y[index] = tmp; + } + + if(tsOrientation & TS_SWAP_X) + { + Raw_x[index] = FT_6206_MAX_WIDTH_HEIGHT - 1 - Raw_x[index]; + } + + if(tsOrientation & TS_SWAP_Y) + { + Raw_y[index] = FT_6206_MAX_WIDTH_HEIGHT - 1 - Raw_y[index]; + } + + xDiff = Raw_x[index] > _x[index]? (Raw_x[index] - _x[index]): (_x[index] - Raw_x[index]); + yDiff = Raw_y[index] > _y[index]? (Raw_y[index] - _y[index]): (_y[index] - Raw_y[index]); + + if ((xDiff + yDiff) > 5) + { + _x[index] = Raw_x[index]; + _y[index] = Raw_y[index]; + } + + + TS_State->touchX[index] = _x[index]; + TS_State->touchY[index] = _y[index]; + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + + /* Get touch info related to the current touch */ + ft6x06_TS_GetTouchInfo(I2C_Address, index, &weight, &area, &event); + + /* Update TS_State structure */ + TS_State->touchWeight[index] = weight; + TS_State->touchArea[index] = area; + + /* Remap touch event */ + switch(event) + { + case FT6206_TOUCH_EVT_FLAG_PRESS_DOWN : + TS_State->touchEventId[index] = TOUCH_EVENT_PRESS_DOWN; + break; + case FT6206_TOUCH_EVT_FLAG_LIFT_UP : + TS_State->touchEventId[index] = TOUCH_EVENT_LIFT_UP; + break; + case FT6206_TOUCH_EVT_FLAG_CONTACT : + TS_State->touchEventId[index] = TOUCH_EVENT_CONTACT; + break; + case FT6206_TOUCH_EVT_FLAG_NO_EVENT : + TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT; + break; + default : + ts_status = TS_ERROR; + break; + } /* of switch(event) */ + +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + } /* of for(index=0; index < TS_State->touchDetected; index++) */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + /* Get gesture Id */ + ts_status = BSP_TS_Get_GestureId(TS_State); +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + } /* end of if(TS_State->touchDetected != 0) */ + + return (ts_status); +} + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +/** + * @brief Update gesture Id following a touch detected. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State) +{ + uint32_t gestureId = 0; + uint8_t ts_status = TS_OK; + + /* Get gesture Id */ + ft6x06_TS_GetGestureID(I2C_Address, &gestureId); + + /* Remap gesture Id to a TS_GestureIdTypeDef value */ + switch(gestureId) + { + case FT6206_GEST_ID_NO_GESTURE : + TS_State->gestureId = GEST_ID_NO_GESTURE; + break; + case FT6206_GEST_ID_MOVE_UP : + TS_State->gestureId = GEST_ID_MOVE_UP; + break; + case FT6206_GEST_ID_MOVE_RIGHT : + TS_State->gestureId = GEST_ID_MOVE_RIGHT; + break; + case FT6206_GEST_ID_MOVE_DOWN : + TS_State->gestureId = GEST_ID_MOVE_DOWN; + break; + case FT6206_GEST_ID_MOVE_LEFT : + TS_State->gestureId = GEST_ID_MOVE_LEFT; + break; + case FT6206_GEST_ID_ZOOM_IN : + TS_State->gestureId = GEST_ID_ZOOM_IN; + break; + case FT6206_GEST_ID_ZOOM_OUT : + TS_State->gestureId = GEST_ID_ZOOM_OUT; + break; + default : + ts_status = TS_ERROR; + break; + } /* of switch(gestureId) */ + + return(ts_status); +} +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + +/** @defgroup STM32F723E-DISCOVERY_TS_Private_Functions TS Private Functions + * @{ + */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +/** + * @brief Function used to reset all touch data before a new acquisition + * of touch information. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if OK, TE_ERROR if problem found. + */ +uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State) +{ + uint8_t ts_status = TS_ERROR; + uint32_t index; + + if (TS_State != (TS_StateTypeDef *)NULL) + { + TS_State->gestureId = GEST_ID_NO_GESTURE; + TS_State->touchDetected = 0; + + for(index = 0; index < TS_MAX_NB_TOUCH; index++) + { + TS_State->touchX[index] = 0; + TS_State->touchY[index] = 0; + TS_State->touchArea[index] = 0; + TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT; + TS_State->touchWeight[index] = 0; + } + + ts_status = TS_OK; + + } /* of if (TS_State != (TS_StateTypeDef *)NULL) */ + + return (ts_status); +} +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +/** + * @brief Initializes the TS_INT pin MSP. + * @retval None + */ +__weak void BSP_TS_INT_MspInit(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + TS_INT_GPIO_CLK_ENABLE(); + + /* GPIO configuration in input for TouchScreen interrupt signal on TS_INT pin */ + gpio_init_structure.Pin = TS_INT_PIN; + + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(TS_INT_GPIO_PORT, &gpio_init_structure); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_ts.h b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_ts.h new file mode 100644 index 00000000..6c7c4601 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F723E-Discovery/stm32f723e_discovery_ts.h @@ -0,0 +1,215 @@ +/** + ****************************************************************************** + * @file stm32f723e_discovery_ts.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f723E_discovery_ts.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F723E_DISCOVERY_TS_H +#define __STM32F723E_DISCOVERY_TS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f723e_discovery.h" + +/* Include TouchScreen component driver */ +#include "../Components/ft6x06/ft6x06.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F723E_DISCOVERY_TS STM32F723E-DISCOVERY TS + * @{ + */ + + /** @defgroup STM32F723E-DISCOVERY_TS_Exported_Constants TS Exported Constants + * @{ + */ +/** @brief With FT6206 : maximum 2 touches detected simultaneously + */ +#define TS_MAX_NB_TOUCH ((uint32_t) FT6206_MAX_DETECTABLE_TOUCH) + +#define TS_NO_IRQ_PENDING ((uint8_t) 0) +#define TS_IRQ_PENDING ((uint8_t) 1) + +#define TS_SWAP_NONE ((uint8_t) 0x01) +#define TS_SWAP_X ((uint8_t) 0x02) +#define TS_SWAP_Y ((uint8_t) 0x04) +#define TS_SWAP_XY ((uint8_t) 0x08) + +#define TS_ORIENTATION_PORTRAIT ((uint8_t) 0x00) +#define TS_ORIENTATION_LANDSCAPE ((uint8_t) 0x01) +#define TS_ORIENTATION_LANDSCAPE_ROT180 ((uint8_t) 0x02) + + /** + * @} + */ + +/** @defgroup STM32F723E-DISCOVERY_TS_Exported_Types TS Exported Types + * @{ + */ +/** +* @brief TS_StateTypeDef +* Define TS State structure +*/ +typedef struct +{ + uint8_t touchDetected; /*!< Total number of active touches detected at last scan */ + uint16_t touchX[TS_MAX_NB_TOUCH]; /*!< Touch X[0], X[1] coordinates on 12 bits */ + uint16_t touchY[TS_MAX_NB_TOUCH]; /*!< Touch Y[0], Y[1] coordinates on 12 bits */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + uint8_t touchWeight[TS_MAX_NB_TOUCH]; /*!< Touch_Weight[0], Touch_Weight[1] : weight property of touches */ + uint8_t touchEventId[TS_MAX_NB_TOUCH]; /*!< Touch_EventId[0], Touch_EventId[1] : take value of type @ref TS_TouchEventTypeDef */ + uint8_t touchArea[TS_MAX_NB_TOUCH]; /*!< Touch_Area[0], Touch_Area[1] : touch area of each touch */ + uint32_t gestureId; /*!< type of gesture detected : take value of type @ref TS_GestureIdTypeDef */ +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +} TS_StateTypeDef; + +/** + * @brief TS_StatusTypeDef + * Define BSP_TS_xxx() functions possible return value, + * when status is returned by those functions. + */ +typedef enum +{ + TS_OK = 0x00, /*!< Touch Ok */ + TS_ERROR = 0x01, /*!< Touch Error */ + TS_TIMEOUT = 0x02, /*!< Touch Timeout */ + TS_DEVICE_NOT_FOUND = 0x03 /*!< Touchscreen device not found */ +} TS_StatusTypeDef; + +/** + * @brief TS_GestureIdTypeDef + * Define Possible managed gesture identification values returned by touch screen + * driver. + */ +typedef enum +{ + GEST_ID_NO_GESTURE = 0x00, /*!< Gesture not defined / recognized */ + GEST_ID_MOVE_UP = 0x01, /*!< Gesture Move Up */ + GEST_ID_MOVE_RIGHT = 0x02, /*!< Gesture Move Right */ + GEST_ID_MOVE_DOWN = 0x03, /*!< Gesture Move Down */ + GEST_ID_MOVE_LEFT = 0x04, /*!< Gesture Move Left */ + GEST_ID_ZOOM_IN = 0x05, /*!< Gesture Zoom In */ + GEST_ID_ZOOM_OUT = 0x06, /*!< Gesture Zoom Out */ + GEST_ID_NB_MAX = 0x07 /*!< max number of gesture id */ +} TS_GestureIdTypeDef; + +/** + * @brief TS_TouchEventTypeDef + * Define Possible touch events kind as returned values + * by touch screen IC Driver. + */ +typedef enum +{ + TOUCH_EVENT_NO_EVT = 0x00, /*!< Touch Event : undetermined */ + TOUCH_EVENT_PRESS_DOWN = 0x01, /*!< Touch Event Press Down */ + TOUCH_EVENT_LIFT_UP = 0x02, /*!< Touch Event Lift Up */ + TOUCH_EVENT_CONTACT = 0x03, /*!< Touch Event Contact */ + TOUCH_EVENT_NB_MAX = 0x04 /*!< max number of touch events kind */ +} TS_TouchEventTypeDef; + +/** + * @} + */ + +/** @addtogroup STM32F723E-DISCOVERY_TS_Imported_Variables TS Imported Variables + * @{ + */ +/** + * @brief Table for touchscreen event information display on LCD : + * table indexed on enum @ref TS_TouchEventTypeDef information + */ +extern char * ts_event_string_tab[TOUCH_EVENT_NB_MAX]; + +/** + * @brief Table for touchscreen gesture Id information display on LCD : table indexed + * on enum @ref TS_GestureIdTypeDef information + */ +extern char * ts_gesture_id_string_tab[GEST_ID_NB_MAX]; +/** + * @} + */ + +/** @defgroup STM32F723E-DISCOVERY_TS_Exported_Functions TS Exported Functions + * @{ + */ +uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY); +uint8_t BSP_TS_InitEx(uint16_t ts_SizeX, uint16_t ts_SizeY, uint8_t orientation); +uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State); + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State); +uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State); +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +uint8_t BSP_TS_ITConfig(void); + +/* These __weak function can be surcharged by application code in case the current settings + need to be changed for specific (example GPIO allocation) */ +void BSP_TS_INT_MspInit(void); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F723E_DISCOVERY_TS_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/Release_Notes.html new file mode 100644 index 00000000..f0a40823 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/Release_Notes.html @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + Release Notes for STM32F723E-Discovery Kit BSP Drivers + + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for STM32F7308-Discovery Board Drivers

+

Copyright +2018 STMicroelectronics

+

+
+

 

+ + + + + + +

The BSP (Board Specific +Package) drivers are parts of the STM32Cube package based on the HAL +drivers and provide a set of high level APIs relative to the hardware +components and features in the evaluation boards, discovery kits and nucleo +boards coming with the STM32Cube package for a given STM32 serie.

+

The BSP drivers allow a quick access to the boards’ +services using high level APIs and without any specific configuration as the +link with the HAL and the external components is done in intrinsic within the drivers.
+

+

From project settings points of view, user has only +to add the necessary driver’s files in the workspace and call the needed +functions from examples. However some low level +configuration functions are weak and can be overridden by the applications if user +wants to change some BSP drivers default behavior.

+ + +

    Update History

V1.0.0 / 19-October-2018

+ +

Main +Changes

+
    +
  • First official Release for STM32F7308-Discovery +board drivers.

Dependencies

+ + + + + + +
  • STM32F7xx_HAL_Driver V1.2.6
    +
  • BSP Common V4.0.1

License

+
+

This software component is licensed by ST under BSD 3-Clause +license, the "License"; You may not use this component except +in compliance with the License. You may obtain a copy of the License at:

+ +

https://opensource.org/licenses/BSD-3-Clause

+
+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery.c b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery.c new file mode 100644 index 00000000..d208bd53 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery.c @@ -0,0 +1,1037 @@ +/** + ****************************************************************************** + * @file stm32f7308_discovery.c + * @author MCD Application Team + * @brief This file provides a set of firmware functions to manage LEDs, + * push-buttons, external PSRAM, external QSPI Flash, TS available on + * STM32F7308-Discovery board (MB1260) from STMicroelectronics. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_uart.c +- stm32f7xx_hal_i2c.c +- stm32f7xx_hal_sram.c +- stm32f7xx_hal_rcc_ex.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7308_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_LOW_LEVEL STM32F7308_DISCOVERY_LOW_LEVEL + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_LOW_LEVEL_Private_TypesDefinitions STM32F7308 Discovery Low Level Private Typedef + * @{ + */ +typedef struct +{ + __IO uint16_t REG; + __IO uint16_t RAM; +}LCD_CONTROLLER_TypeDef; +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LOW_LEVEL_Private_Defines LOW_LEVEL Private Defines + * @{ + */ +/** + * @brief STM32F7308 Discovery BSP Driver version number V1.0.2 + */ +#define __STM32F7308_DISCOVERY_BSP_VERSION_MAIN (0x01) /*!< [31:24] main version */ +#define __STM32F7308_DISCOVERY_BSP_VERSION_SUB1 (0x00) /*!< [23:16] sub1 version */ +#define __STM32F7308_DISCOVERY_BSP_VERSION_SUB2 (0x02) /*!< [15:8] sub2 version */ +#define __STM32F7308_DISCOVERY_BSP_VERSION_RC (0x00) /*!< [7:0] release candidate */ +#define __STM32F7308_DISCOVERY_BSP_VERSION ((__STM32F7308_DISCOVERY_BSP_VERSION_MAIN << 24)\ + |(__STM32F7308_DISCOVERY_BSP_VERSION_SUB1 << 16)\ + |(__STM32F7308_DISCOVERY_BSP_VERSION_SUB2 << 8 )\ + |(__STM32F7308_DISCOVERY_BSP_VERSION_RC)) + +/* We use BANK2 as we use FMC_NE2 signal */ +#define FMC_BANK2_BASE ((uint32_t)(0x60000000 | 0x04000000)) +#define FMC_BANK2 ((LCD_CONTROLLER_TypeDef *) FMC_BANK2_BASE) +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LOW_LEVEL_Private_Macros LOW_LEVEL Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LOW_LEVEL_Private_Variables LOW_LEVEL Private Variables + * @{ + */ +uint32_t GPIO_PIN[LEDn] = {LED5_PIN, + LED6_PIN}; + +GPIO_TypeDef* GPIO_PORT[LEDn] = {LED5_GPIO_PORT, + LED6_GPIO_PORT}; + +GPIO_TypeDef* BUTTON_PORT[BUTTONn] = {WAKEUP_BUTTON_GPIO_PORT }; + +const uint16_t BUTTON_PIN[BUTTONn] = {WAKEUP_BUTTON_PIN }; + +const uint16_t BUTTON_IRQn[BUTTONn] = {WAKEUP_BUTTON_EXTI_IRQn }; + +USART_TypeDef* COM_USART[COMn] = {DISCOVERY_COM1}; + +GPIO_TypeDef* COM_TX_PORT[COMn] = {DISCOVERY_COM1_TX_GPIO_PORT}; + +GPIO_TypeDef* COM_RX_PORT[COMn] = {DISCOVERY_COM1_RX_GPIO_PORT}; + +const uint16_t COM_TX_PIN[COMn] = {DISCOVERY_COM1_TX_PIN}; + +const uint16_t COM_RX_PIN[COMn] = {DISCOVERY_COM1_RX_PIN}; + +const uint16_t COM_TX_AF[COMn] = {DISCOVERY_COM1_TX_AF}; + +const uint16_t COM_RX_AF[COMn] = {DISCOVERY_COM1_RX_AF}; + +static I2C_HandleTypeDef hI2cAudioHandler = {0}; +static I2C_HandleTypeDef hI2cTsHandler = {0}; + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LOW_LEVEL_Private_FunctionPrototypes LOW_LEVEL Private FunctionPrototypes + * @{ + */ +static void I2Cx_MspInit(I2C_HandleTypeDef *i2c_handler); +static void I2Cx_Init(I2C_HandleTypeDef *i2c_handler); + +static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static void I2Cx_Error(I2C_HandleTypeDef *i2c_handler, uint8_t Addr); + +static void FMC_BANK2_WriteData(uint16_t Data); +static void FMC_BANK2_WriteReg(uint8_t Reg); +static uint16_t FMC_BANK2_ReadData(void); +static void FMC_BANK2_Init(void); +static void FMC_BANK2_MspInit(void); + +/* LCD IO functions */ +void LCD_IO_Init(void); +void LCD_IO_WriteData(uint16_t RegValue); +void LCD_IO_WriteReg(uint8_t Reg); +void LCD_IO_WriteMultipleData(uint16_t *pData, uint32_t Size); +uint16_t LCD_IO_ReadData(void); +void LCD_IO_Delay(uint32_t Delay); + +/* AUDIO IO functions */ +void AUDIO_IO_Init(void); +void AUDIO_IO_DeInit(void); +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value); +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg); +void AUDIO_IO_Delay(uint32_t Delay); + +/* TouchScreen (TS) IO functions */ +void TS_IO_Init(void); +void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg); +uint16_t TS_IO_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); +void TS_IO_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); +void TS_IO_Delay(uint32_t Delay); + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_BSP_Public_Functions BSP Public Functions + * @{ + */ + + /** + * @brief This method returns the STM32F7308 Discovery BSP Driver revision + * @retval version: 0xXYZR (8bits for each decimal, R for RC) + */ +uint32_t BSP_GetVersion(void) +{ + return __STM32F7308_DISCOVERY_BSP_VERSION; +} + +/** + * @brief Configures LED GPIO. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED5 + * @arg LED6 + * @retval None + */ +void BSP_LED_Init(Led_TypeDef Led) +{ + GPIO_InitTypeDef gpio_init_structure; + + LEDx_GPIO_CLK_ENABLE(Led); + /* Configure the GPIO_LED pin */ + gpio_init_structure.Pin = GPIO_PIN[Led]; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + + HAL_GPIO_Init(GPIO_PORT[Led], &gpio_init_structure); + +} + + +/** + * @brief DeInit LEDs. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED5 + * @arg LED6 + * @note Led DeInit does not disable the GPIO clock + * @retval None + */ +void BSP_LED_DeInit(Led_TypeDef Led) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* DeInit the GPIO_LED pin */ + gpio_init_structure.Pin = GPIO_PIN[Led]; + + /* Turn off LED */ + HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_RESET); + HAL_GPIO_DeInit(GPIO_PORT[Led], gpio_init_structure.Pin); +} + +/** + * @brief Turns selected LED On. + * @param Led: LED to be set on + * This parameter can be one of the following values: + * @arg LED5 + * @arg LED6 + * @retval None + */ +void BSP_LED_On(Led_TypeDef Led) +{ + HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_SET); +} + +/** + * @brief Turns selected LED Off. + * @param Led: LED to be set off + * This parameter can be one of the following values: + * @arg LED5 + * @arg LED6 + * @retval None + */ +void BSP_LED_Off(Led_TypeDef Led) +{ + HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_RESET); +} + +/** + * @brief Toggles the selected LED. + * @param Led: LED to be toggled + * This parameter can be one of the following values: + * @arg LED5 + * @arg LED6 + * @retval None + */ +void BSP_LED_Toggle(Led_TypeDef Led) +{ + HAL_GPIO_TogglePin(GPIO_PORT[Led], GPIO_PIN[Led]); +} + +/** + * @brief Configures button GPIO and EXTI Line. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_USER: User Push Button + * @param Button_Mode: Button mode + * This parameter can be one of the following values: + * @arg BUTTON_MODE_GPIO: Button will be used as simple IO + * @arg BUTTON_MODE_EXTI: Button will be connected to EXTI line + * with interrupt generation capability + * @retval None + */ +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable the BUTTON clock */ + BUTTON_GPIO_CLK_ENABLE(); + + if(Button_Mode == BUTTON_MODE_GPIO) + { + /* Configure Button pin as input */ + gpio_init_structure.Pin = BUTTON_PIN[Button]; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure); + } + + if(Button_Mode == BUTTON_MODE_EXTI) + { + /* Configure Button pin as input with External interrupt */ + gpio_init_structure.Pin = BUTTON_PIN[Button]; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + + gpio_init_structure.Mode = GPIO_MODE_IT_RISING; + + HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure); + + /* Enable and set Button EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(BUTTON_IRQn[Button]), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + } +} + +/** + * @brief Push Button DeInit. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_USER: User Push Button + * @note PB DeInit does not disable the GPIO clock + * @retval None + */ +void BSP_PB_DeInit(Button_TypeDef Button) +{ + GPIO_InitTypeDef gpio_init_structure; + + gpio_init_structure.Pin = BUTTON_PIN[Button]; + HAL_NVIC_DisableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + HAL_GPIO_DeInit(BUTTON_PORT[Button], gpio_init_structure.Pin); +} + + +/** + * @brief Returns the selected button state. + * @param Button: Button to be checked + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_USER: User Push Button + * @retval The Button GPIO pin value + */ +uint32_t BSP_PB_GetState(Button_TypeDef Button) +{ + return HAL_GPIO_ReadPin(BUTTON_PORT[Button], BUTTON_PIN[Button]); +} + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LOW_LEVEL_Private_Functions STM32F7308_DISCOVERY_LOW_LEVEL Private Functions + * @{ + */ +/** + * @brief Configures COM port. + * @param COM: COM port to be configured. + * This parameter can be one of the following values: + * @arg COM1 + * @param huart: Pointer to a UART_HandleTypeDef structure that contains the + * configuration information for the specified USART peripheral. + * @retval None + */ +void BSP_COM_Init(COM_TypeDef COM, UART_HandleTypeDef *huart) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable GPIO clock */ + DISCOVERY_COMx_TX_GPIO_CLK_ENABLE(COM); + DISCOVERY_COMx_RX_GPIO_CLK_ENABLE(COM); + + /* Enable USART clock */ + DISCOVERY_COMx_CLK_ENABLE(COM); + + /* Configure USART Tx as alternate function */ + gpio_init_structure.Pin = COM_TX_PIN[COM]; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Alternate = COM_TX_AF[COM]; + HAL_GPIO_Init(COM_TX_PORT[COM], &gpio_init_structure); + + /* Configure USART Rx as alternate function */ + gpio_init_structure.Pin = COM_RX_PIN[COM]; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = COM_RX_AF[COM]; + HAL_GPIO_Init(COM_RX_PORT[COM], &gpio_init_structure); + + /* USART configuration */ + huart->Instance = COM_USART[COM]; + HAL_UART_Init(huart); +} + +/** + * @brief DeInit COM port. + * @param COM: COM port to be configured. + * This parameter can be one of the following values: + * @arg COM1 + * @arg COM2 + * @param huart: Pointer to a UART_HandleTypeDef structure that contains the + * configuration information for the specified USART peripheral. + * @retval None + */ +void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart) +{ + /* USART configuration */ + huart->Instance = COM_USART[COM]; + HAL_UART_DeInit(huart); + + /* Enable USART clock */ + DISCOVERY_COMx_CLK_DISABLE(COM); + + /* DeInit GPIO pins can be done in the application + (by surcharging this __weak function) */ + + /* GPIO pins clock, FMC clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/******************************************************************************* + BUS OPERATIONS +*******************************************************************************/ + +/******************************* I2C Routines *********************************/ +/** + * @brief Initializes I2C MSP. + * @param i2c_handler : I2C handler + * @retval None + */ +static void I2Cx_MspInit(I2C_HandleTypeDef *i2c_handler) +{ + GPIO_InitTypeDef gpio_init_structure; + + if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cAudioHandler)) + { + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + DISCOVERY_AUDIO_I2Cx_SCL_GPIO_CLK_ENABLE(); + DISCOVERY_AUDIO_I2Cx_SDA_GPIO_CLK_ENABLE(); + /* Configure I2C Tx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_AUDIO_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = DISCOVERY_AUDIO_I2Cx_SCL_AF; + HAL_GPIO_Init(DISCOVERY_AUDIO_I2Cx_SCL_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C Rx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_AUDIO_I2Cx_SDA_PIN; + gpio_init_structure.Alternate = DISCOVERY_AUDIO_I2Cx_SDA_AF; + HAL_GPIO_Init(DISCOVERY_AUDIO_I2Cx_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + DISCOVERY_AUDIO_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + DISCOVERY_AUDIO_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + DISCOVERY_AUDIO_I2Cx_RELEASE_RESET(); + + /* Enable and set I2C1 Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_AUDIO_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_AUDIO_I2Cx_EV_IRQn); + + /* Enable and set I2C1 Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_AUDIO_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_AUDIO_I2Cx_ER_IRQn); + + } + else if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cTsHandler)) + { + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + TS_I2Cx_SCL_GPIO_CLK_ENABLE(); + TS_I2Cx_SDA_GPIO_CLK_ENABLE(); + /* Configure I2C SCL as alternate function */ + gpio_init_structure.Pin = TS_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; + gpio_init_structure.Alternate = TS_I2Cx_SCL_AF; + HAL_GPIO_Init(TS_I2Cx_SCL_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C SDA as alternate function */ + gpio_init_structure.Pin = TS_I2Cx_SDA_PIN; + gpio_init_structure.Alternate = TS_I2Cx_SDA_AF; + HAL_GPIO_Init(TS_I2Cx_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + TS_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + TS_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + TS_I2Cx_RELEASE_RESET(); + + /* Enable and set I2C Interrupt to a lower priority */ + HAL_NVIC_SetPriority(TS_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(TS_I2Cx_EV_IRQn); + + /* Enable and set I2C Interrupt to a lower priority */ + HAL_NVIC_SetPriority(TS_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(TS_I2Cx_ER_IRQn); + + } + else + { + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_CLK_ENABLE(); + + /* Configure I2C Tx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_EXT_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = DISCOVERY_EXT_I2Cx_SCL_SDA_AF; + HAL_GPIO_Init(DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C Rx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_EXT_I2Cx_SDA_PIN; + HAL_GPIO_Init(DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + DISCOVERY_EXT_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + DISCOVERY_EXT_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + DISCOVERY_EXT_I2Cx_RELEASE_RESET(); + + /* Enable and set I2C1 Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_EXT_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_EXT_I2Cx_EV_IRQn); + + /* Enable and set I2C1 Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_EXT_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_EXT_I2Cx_ER_IRQn); + } +} + +/** + * @brief Initializes I2C HAL. + * @param i2c_handler : I2C handler + * @retval None + */ +static void I2Cx_Init(I2C_HandleTypeDef *i2c_handler) +{ + if(HAL_I2C_GetState(i2c_handler) == HAL_I2C_STATE_RESET) + { + if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cAudioHandler)) + { + /* Audio and LCD I2C configuration */ + i2c_handler->Instance = DISCOVERY_AUDIO_I2Cx; + } + else if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cTsHandler)) + { + /* TouchScreen I2C configuration */ + i2c_handler->Instance = TS_I2Cx; + } + else + { + /* External, camera and Arduino connector I2C configuration */ + i2c_handler->Instance = DISCOVERY_EXT_I2Cx; + } + i2c_handler->Init.Timing = DISCOVERY_I2Cx_TIMING; + i2c_handler->Init.OwnAddress1 = 0; + i2c_handler->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + i2c_handler->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + i2c_handler->Init.OwnAddress2 = 0; + i2c_handler->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + i2c_handler->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + + /* Init the I2C */ + I2Cx_MspInit(i2c_handler); + HAL_I2C_Init(i2c_handler); + } +} + +/** + * @brief Reads multiple data. + * @param i2c_handler : I2C handler + * @param Addr: I2C address + * @param Reg: Reg address + * @param MemAddress: memory address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddress, uint8_t *Buffer, uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Read(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* I2C error occured */ + I2Cx_Error(i2c_handler, Addr); + } + return status; +} + + +/** + * @brief Writes a value in a register of the device through BUS in using DMA mode. + * @param i2c_handler : I2C handler + * @param Addr: Device address on BUS Bus. + * @param Reg: The target register address to write + * @param MemAddress: memory address + * @param Buffer: The target register value to be written + * @param Length: buffer size to be written + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddress, uint8_t *Buffer, uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Write(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* Re-Initiaize the I2C Bus */ + I2Cx_Error(i2c_handler, Addr); + } + return status; +} + + +/** + * @brief Manages error callback by re-initializing I2C. + * @param i2c_handler : I2C handler + * @param Addr: I2C Address + * @retval None + */ +static void I2Cx_Error(I2C_HandleTypeDef *i2c_handler, uint8_t Addr) +{ + /* De-initialize the I2C communication bus */ + HAL_I2C_DeInit(i2c_handler); + + /* Re-Initialize the I2C communication bus */ + I2Cx_Init(i2c_handler); +} + +/** + * @} + */ + +/******************************************************************************* + LINK OPERATIONS +*******************************************************************************/ +/*************************** FMC Routines *************************************/ +/** + * @brief Initializes FMC_BANK2 MSP. + * @retval None + */ +static void FMC_BANK2_MspInit(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable FMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + + /* Enable FSMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + __HAL_RCC_FMC_FORCE_RESET(); + __HAL_RCC_FMC_RELEASE_RESET(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = GPIO_AF12_FMC; + + /* GPIOD configuration */ + /* LCD_PSRAM_D2, LCD_PSRAM_D3, LCD_PSRAM_NOE, LCD_PSRAM_NWE, PSRAM_NE1, LCD_PSRAM_D13, + LCD_PSRAM_D14, LCD_PSRAM_D15, PSRAM_A16, PSRAM_A17, LCD_PSRAM_D0, LCD_PSRAM_D1 */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7 | GPIO_PIN_8 |\ + GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOE configuration */ + /* PSRAM_NBL0, PSRAM_NBL1, LCD_PSRAM_D4, LCD_PSRAM_D5, LCD_PSRAM_D6, LCD_PSRAM_D7, + LCD_PSRAM_D8, LCD_PSRAM_D9, LCD_PSRAM_D10, LCD_PSRAM_D11, LCD_PSRAM_D12 */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 |GPIO_PIN_10 |\ + GPIO_PIN_11 | GPIO_PIN_12 |GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOF configuration */ + /* PSRAM_A0, PSRAM_A1, PSRAM_A2, PSRAM_A3, PSRAM_A4, PSRAM_A5, + PSRAM_A6, PSRAM_A7, PSRAM_A8, PSRAM_A9 */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 |\ + GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOF, &gpio_init_structure); + + /* GPIOG configuration */ + /* PSRAM_A10, PSRAM_A11, PSRAM_A12, PSRAM_A13, PSRAM_A14, PSRAM_A15, LCD_NE */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 |\ + GPIO_PIN_9 ; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); +} + + +/** + * @brief Initializes LCD IO. + * @retval None + */ +static void FMC_BANK2_Init(void) +{ + SRAM_HandleTypeDef hsram; + FMC_NORSRAM_TimingTypeDef sram_timing; + + /* GPIO configuration for FMC signals (LCD) */ + FMC_BANK2_MspInit(); + + /* PSRAM device configuration */ + hsram.Instance = FMC_NORSRAM_DEVICE; + hsram.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + /* Set parameters for LCD access (FMC_NORSRAM_BANK2) */ + hsram.Init.NSBank = FMC_NORSRAM_BANK2; + hsram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; + hsram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM; + hsram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16; + hsram.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE; + hsram.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; + hsram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; + hsram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; + hsram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE; + hsram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; + hsram.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE; + hsram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE; + hsram.Init.WriteFifo = FMC_WRITE_FIFO_DISABLE; + hsram.Init.PageSize = FMC_PAGE_SIZE_NONE; + hsram.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY; + + /* PSRAM device configuration */ + /* Timing configuration derived from system clock (up to 216Mhz) + for 108Mhz as PSRAM clock frequency */ + sram_timing.AddressSetupTime = 9; + sram_timing.AddressHoldTime = 2; + sram_timing.DataSetupTime = 6; + sram_timing.BusTurnAroundDuration = 1; + sram_timing.CLKDivision = 2; + sram_timing.DataLatency = 2; + sram_timing.AccessMode = FMC_ACCESS_MODE_A; + + /* Initialize the FMC controller for LCD (FMC_NORSRAM_BANK2) */ + HAL_SRAM_Init(&hsram, &sram_timing, &sram_timing); +} + +/** + * @brief Writes register value. + * @param Data: Data to be written + * @retval None + */ +static void FMC_BANK2_WriteData(uint16_t Data) +{ + /* Write 16-bit Reg */ + FMC_BANK2->RAM = Data; + __DSB(); +} + +/** + * @brief Writes register address. + * @param Reg: Register to be written + * @retval None + */ +static void FMC_BANK2_WriteReg(uint8_t Reg) +{ + /* Write 16-bit Index, then write register */ + FMC_BANK2->REG = Reg; + __DSB(); +} + +/** + * @brief Reads register value. + * @retval Read value + */ +static uint16_t FMC_BANK2_ReadData(void) +{ + return FMC_BANK2->RAM; +} + +/******************************************************************************* + LINK OPERATIONS +*******************************************************************************/ + +/********************************* LINK LCD ***********************************/ + +/** + * @brief Initializes LCD low level. + * @retval None + */ +void LCD_IO_Init(void) +{ + FMC_BANK2_Init(); +} + +/** + * @brief Writes data on LCD data register. + * @param RegValue: Register value to be written + * @retval None + */ +void LCD_IO_WriteData(uint16_t RegValue) +{ + /* Write 16-bit Reg */ + FMC_BANK2_WriteData(RegValue); + __DSB(); +} + +/** + * @brief Writes several data on LCD data register. + * @param pData: pointer on data to be written + * @param Size: data amount in 16bits short unit + * @retval None + */ +void LCD_IO_WriteMultipleData(uint16_t *pData, uint32_t Size) +{ + uint32_t i; + + for (i = 0; i < Size; i++) + { + FMC_BANK2_WriteData(pData[i]); + __DSB(); + } +} + +/** + * @brief Writes register on LCD register. + * @param Reg: Register to be written + * @retval None + */ +void LCD_IO_WriteReg(uint8_t Reg) +{ + /* Write 16-bit Index, then Write Reg */ + FMC_BANK2_WriteReg(Reg); + __DSB(); +} + +/** + * @brief Reads data from LCD data register. + * @retval Read data. + */ +uint16_t LCD_IO_ReadData(void) +{ + return FMC_BANK2_ReadData(); +} + +/** + * @brief LCD delay + * @param Delay: Delay in ms + * @retval None + */ +void LCD_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/********************************* LINK AUDIO *********************************/ + +/** + * @brief Initializes Audio low level. + */ +void AUDIO_IO_Init(void) +{ + I2Cx_Init(&hI2cAudioHandler); +} + +/** + * @brief DeInitializes Audio low level. + */ +void AUDIO_IO_DeInit(void) +{ + +} + +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param Value: Data to be written + * @retval None + */ +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value) +{ + uint16_t tmp = Value; + + Value = ((uint16_t)(tmp >> 8) & 0x00FF); + + Value |= ((uint16_t)(tmp << 8)& 0xFF00); + + I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_16BIT,(uint8_t*)&Value, 2); +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @retval Data to be read + */ +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg) +{ + uint16_t read_value = 0, tmp = 0; + + I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&read_value, 2); + + tmp = ((uint16_t)(read_value >> 8) & 0x00FF); + + tmp |= ((uint16_t)(read_value << 8)& 0xFF00); + + read_value = tmp; + + return read_value; +} + +/** + * @brief AUDIO Codec delay + * @param Delay: Delay in ms + */ +void AUDIO_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/******************************** LINK TS (TouchScreen) ***********************/ + +/** + * @brief Initializes Touchscreen low level. + * @retval None + */ +void TS_IO_Init(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + TS_RESET_GPIO_CLK_ENABLE(); + + /* Configure Button pin as input */ + gpio_init_structure.Pin = TS_RESET_PIN; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(TS_RESET_GPIO_PORT, &gpio_init_structure); + HAL_GPIO_WritePin(TS_RESET_GPIO_PORT, TS_RESET_PIN, GPIO_PIN_SET); + I2Cx_Init(&hI2cTsHandler); +} + +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param Value: Data to be written + * @retval None + */ +void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_WriteMultiple(&hI2cTsHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT,(uint8_t*)&Value, 1); +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @retval Data to be read + */ +uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg) +{ + uint8_t read_value = 0; + + I2Cx_ReadMultiple(&hI2cTsHandler, Addr, Reg, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&read_value, 1); + + return read_value; +} + +/** + * @brief Reads multiple data with I2C communication + * channel from TouchScreen. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval Number of read data + */ +uint16_t TS_IO_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + return I2Cx_ReadMultiple(&hI2cTsHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief Writes multiple data with I2C communication + * channel from MCU to TouchScreen. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval None + */ +void TS_IO_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + I2Cx_WriteMultiple(&hI2cTsHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief Delay function used in TouchScreen low level driver. + * @param Delay: Delay in ms + * @retval None + */ +void TS_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery.h b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery.h new file mode 100644 index 00000000..10d40247 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery.h @@ -0,0 +1,395 @@ +/** + ****************************************************************************** + * @file stm32f7308_discovery.h + * @author MCD Application Team + * @brief This file contains definitions for STM32F7308-Discovery LEDs, + * push-buttons hardware resources. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7308_DISCOVERY_H +#define __STM32F7308_DISCOVERY_H + +#ifdef __cplusplus + extern "C" { +#endif + + + /* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY_LOW_LEVEL + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_LOW_LEVEL_Exported_Types STM32F7308 Discovery Low Level Exported Types + * @{ + */ + +/** + * @brief Define for STM32F7308_DISCOVERY board + */ +#if !defined (USE_STM32F7308_DISCO) + #define USE_STM32F7308_DISCO +#endif + +/** @brief Led_TypeDef + * STM32F7308_Discovery board leds definitions. + */ +typedef enum +{ + LED5 = 0, + LED_RED = LED5, + LED6 = 1, + LED_GREEN = LED6 +} Led_TypeDef; + +/** @brief Button_TypeDef + * STM32F7308_Discovery board Buttons definitions. + */ +typedef enum +{ + BUTTON_WAKEUP = 0, +} Button_TypeDef; + +#define BUTTON_USER BUTTON_WAKEUP + +/** @brief ButtonMode_TypeDef + * STM32F7308_Discovery board Buttons Modes definitions. + */ +typedef enum +{ + BUTTON_MODE_GPIO = 0, + BUTTON_MODE_EXTI = 1 + +} ButtonMode_TypeDef; + +typedef enum +{ + PB_SET = 0, + PB_RESET = !PB_SET +} ButtonValue_TypeDef; + +typedef enum +{ + COM1 = 0, +}COM_TypeDef; + +/** @brief DISCO_Status_TypeDef + * STM32F7308_DISCO board Status return possible values. + */ +typedef enum +{ + DISCO_OK = 0, + DISCO_ERROR = 1 + +} DISCO_Status_TypeDef; + +/** + * @} + */ + +/** @addtogroup STM32F7308_DISCOVERY_LOW_LEVEL_LED STM32F7308 Discovery Low Level Led + * @{ + */ +/* Always four leds for all revisions of Discovery boards */ +#define LEDn ((uint8_t)2) + + +/* 2 Leds are connected to MCU directly on PA7 and PB1 */ +#define LED5_GPIO_PORT ((GPIO_TypeDef*)GPIOA) +#define LED6_GPIO_PORT ((GPIO_TypeDef*)GPIOB) + +#define LED5_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define LED6_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() + +#define LED5_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define LED6_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE() + + +#define LEDx_GPIO_CLK_ENABLE(__INDEX__) do{if((__INDEX__) == 0) LED5_GPIO_CLK_ENABLE(); else \ + if((__INDEX__) == 1) LED6_GPIO_CLK_ENABLE(); \ + }while(0) + +#define LEDx_GPIO_CLK_DISABLE(__INDEX__) do{if((__INDEX__) == 0) LED5_GPIO_CLK_DISABLE(); else \ + if((__INDEX__) == 1) LED6_GPIO_CLK_DISABLE(); \ + }while(0) + +#define LED5_PIN ((uint32_t)GPIO_PIN_7) +#define LED6_PIN ((uint32_t)GPIO_PIN_1) + +/** + * @} + */ + +/** @addtogroup STM32F7308_DISCOVERY_LOW_LEVEL_BUTTON STM32F7308 Discovery Low Level Button + * @{ + */ +/* Only one User/Wakeup button */ +#define BUTTONn ((uint8_t)1) + +/** + * @brief Wakeup push-button + */ +#define WAKEUP_BUTTON_PIN GPIO_PIN_0 +#define WAKEUP_BUTTON_GPIO_PORT GPIOA +#define WAKEUP_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define WAKEUP_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define WAKEUP_BUTTON_EXTI_IRQn EXTI0_IRQn + +/* Define the USER button as an alias of the Wakeup button */ +#define USER_BUTTON_PIN WAKEUP_BUTTON_PIN +#define USER_BUTTON_GPIO_PORT WAKEUP_BUTTON_GPIO_PORT +#define USER_BUTTON_GPIO_CLK_ENABLE() WAKEUP_BUTTON_GPIO_CLK_ENABLE() +#define USER_BUTTON_GPIO_CLK_DISABLE() WAKEUP_BUTTON_GPIO_CLK_DISABLE() +#define USER_BUTTON_EXTI_IRQn WAKEUP_BUTTON_EXTI_IRQn + +#define BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LOW_LEVEL_Exported_Constants LOW_LEVEL Exported Constants + * @{ + */ +/** + * @brief USB OTG HS Over Current signal + */ +#define OTG_HS_OVER_CURRENT_PIN GPIO_PIN_10 +#define OTG_HS_OVER_CURRENT_PORT GPIOH +#define OTG_HS_OVER_CURRENT_PORT_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() + +/** + * @brief USB OTG FS Over Current signal + */ +#define OTG_FS_OVER_CURRENT_PIN GPIO_PIN_8 +#define OTG_FS_OVER_CURRENT_PORT GPIOC +#define OTG_FS_OVER_CURRENT_PORT_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() + +/** + * @brief TS_INT signal from TouchScreen + */ +#define TS_INT_PIN ((uint32_t)GPIO_PIN_9) +#define TS_INT_GPIO_PORT ((GPIO_TypeDef*)GPIOI) +#define TS_INT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define TS_INT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define TS_INT_EXTI_IRQn EXTI9_5_IRQn + +/** + * @brief TS RESET pin + */ +#define TS_RESET_PIN GPIO_PIN_9 +#define TS_RESET_GPIO_PORT GPIOH +#define TS_RESET_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() +#define TS_RESET_GPIO_CLK_DISABLE() __HAL_RCC_GPIOH_CLK_DISABLE() +#define TS_RESET_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief Definition for I2C3 Touchscreen Pins + * resources (touchescreen). + * Definition for I2C3 clock resources + */ +#define TS_I2Cx I2C3 +#define TS_I2Cx_CLK_ENABLE() __HAL_RCC_I2C3_CLK_ENABLE() +#define TS_I2Cx_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define TS_I2Cx_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() + +#define TS_I2Cx_FORCE_RESET() __HAL_RCC_I2C3_FORCE_RESET() +#define TS_I2Cx_RELEASE_RESET() __HAL_RCC_I2C3_RELEASE_RESET() + +/** @brief Definition for Touchscreen Pins + */ +#define TS_I2Cx_SCL_PIN GPIO_PIN_8 +#define TS_I2Cx_SCL_AF GPIO_AF4_I2C3 +#define TS_I2Cx_SCL_GPIO_PORT GPIOA +#define TS_I2Cx_SDA_PIN GPIO_PIN_8 +#define TS_I2Cx_SDA_AF GPIO_AF4_I2C3 +#define TS_I2Cx_SDA_GPIO_PORT GPIOH + +#define TS_I2Cx_EV_IRQn I2C3_EV_IRQn +#define TS_I2Cx_ER_IRQn I2C3_ER_IRQn + +/** + * @brief TouchScreen FT6206 Slave I2C address + */ +#define TS_I2C_ADDRESS ((uint16_t)0x70) + +/** + * @} + */ + +/** @addtogroup STM32F7308_DISCOVERY_LOW_LEVEL_COM STM32F7308 DISCOVERY Low Level COM + * @{ + */ +#define COMn ((uint8_t)1) + +/** + * @brief Definition for COM port1, connected to USART2 + */ +#define DISCOVERY_COM1 USART2 +#define DISCOVERY_COM1_CLK_ENABLE() __HAL_RCC_USART2_CLK_ENABLE() +#define DISCOVERY_COM1_CLK_DISABLE() __HAL_RCC_USART2_CLK_DISABLE() + +#define DISCOVERY_COM1_TX_PIN GPIO_PIN_3 +#define DISCOVERY_COM1_TX_GPIO_PORT GPIOA +#define DISCOVERY_COM1_TX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define DISCOVERY_COM1_TX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define DISCOVERY_COM1_TX_AF GPIO_AF7_USART2 + +#define DISCOVERY_COM1_RX_PIN GPIO_PIN_2 +#define DISCOVERY_COM1_RX_GPIO_PORT GPIOA +#define DISCOVERY_COM1_RX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define DISCOVERY_COM1_RX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define DISCOVERY_COM1_RX_AF GPIO_AF7_USART2 + +#define DISCOVERY_COM1_IRQn USART2_IRQn + +#define DISCOVERY_COMx_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) {DISCOVERY_COM1_CLK_ENABLE();} } while(0) +#define DISCOVERY_COMx_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? DISCOVERY_COM1_CLK_DISABLE() : 0) + +#define DISCOVERY_COMx_TX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) {DISCOVERY_COM1_TX_GPIO_CLK_ENABLE();} } while(0) +#define DISCOVERY_COMx_TX_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? DISCOVERY_COM1_TX_GPIO_CLK_DISABLE() : 0) + +#define DISCOVERY_COMx_RX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) {DISCOVERY_COM1_RX_GPIO_CLK_ENABLE();} } while(0) +#define DISCOVERY_COMx_RX_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? DISCOVERY_COM1_RX_GPIO_CLK_DISABLE() : 0) + + +/** + * @brief Audio I2C Slave address + */ +#define AUDIO_I2C_ADDRESS ((uint16_t)0x34) + +/** + * @brief User can use this section to tailor I2C1 instance used and associated + * resources (audio codec). + * Definition for I2C1 clock resources + */ +#define DISCOVERY_AUDIO_I2Cx I2C1 +#define DISCOVERY_AUDIO_I2Cx_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE() +#define DISCOVERY_AUDIO_I2Cx_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define DISCOVERY_AUDIO_I2Cx_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() + +#define DISCOVERY_AUDIO_I2Cx_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET() +#define DISCOVERY_AUDIO_I2Cx_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET() + +/** @brief Definition for I2C1 Pins + */ +#define DISCOVERY_AUDIO_I2Cx_SCL_PIN GPIO_PIN_8 /*!< PB8 */ +#define DISCOVERY_AUDIO_I2Cx_SCL_AF GPIO_AF4_I2C1 +#define DISCOVERY_AUDIO_I2Cx_SCL_GPIO_PORT GPIOB +#define DISCOVERY_AUDIO_I2Cx_SDA_PIN GPIO_PIN_9 /*!< PB9 */ +#define DISCOVERY_AUDIO_I2Cx_SDA_AF GPIO_AF4_I2C1 +#define DISCOVERY_AUDIO_I2Cx_SDA_GPIO_PORT GPIOB +/** @brief Definition of I2C1 interrupt requests + */ +#define DISCOVERY_AUDIO_I2Cx_EV_IRQn I2C1_EV_IRQn +#define DISCOVERY_AUDIO_I2Cx_ER_IRQn I2C1_ER_IRQn + + +/* Definition for external, camera and Arduino connector I2Cx resources */ +#define DISCOVERY_EXT_I2Cx I2C2 +#define DISCOVERY_EXT_I2Cx_CLK_ENABLE() __HAL_RCC_I2C2_CLK_ENABLE() +#define DISCOVERY_EXT_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE() +#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() + +#define DISCOVERY_EXT_I2Cx_FORCE_RESET() __HAL_RCC_I2C2_FORCE_RESET() +#define DISCOVERY_EXT_I2Cx_RELEASE_RESET() __HAL_RCC_I2C2_RELEASE_RESET() + +/* Definition for I2Cx Pins */ +#define DISCOVERY_EXT_I2Cx_SCL_PIN GPIO_PIN_4 +#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT GPIOH +#define DISCOVERY_EXT_I2Cx_SCL_SDA_AF GPIO_AF4_I2C2 +#define DISCOVERY_EXT_I2Cx_SDA_PIN GPIO_PIN_5 + +/* I2C interrupt requests */ +#define DISCOVERY_EXT_I2Cx_EV_IRQn I2C2_EV_IRQn +#define DISCOVERY_EXT_I2Cx_ER_IRQn I2C2_ER_IRQn + + +/* I2C TIMING Register define when I2C clock source is SYSCLK */ +/* I2C TIMING is calculated from APB1 source clock = 50 MHz */ +/* Due to the big MOFSET capacity for adapting the camera level the rising time is very large (>1us) */ +/* 0x40912732 takes in account the big rising and aims a clock of 100khz */ +#ifndef DISCOVERY_I2Cx_TIMING +#define DISCOVERY_I2Cx_TIMING ((uint32_t)0x40912732) +#endif /* DISCOVERY_I2Cx_TIMING */ + + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LOW_LEVEL_Exported_Macros STM32F7308 Discovery Low Level Exported Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LOW_LEVEL_Exported_Functions STM32F7308 Discovery Low Level Exported Functions + * @{ + */ +uint32_t BSP_GetVersion(void); +void BSP_LED_Init(Led_TypeDef Led); +void BSP_LED_DeInit(Led_TypeDef Led); +void BSP_LED_On(Led_TypeDef Led); +void BSP_LED_Off(Led_TypeDef Led); +void BSP_LED_Toggle(Led_TypeDef Led); +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode); +void BSP_PB_DeInit(Button_TypeDef Button); +uint32_t BSP_PB_GetState(Button_TypeDef Button); +void BSP_COM_Init(COM_TypeDef COM, UART_HandleTypeDef *huart); +void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7308_DISCOVERY_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_audio.c b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_audio.c new file mode 100644 index 00000000..b7111a7d --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_audio.c @@ -0,0 +1,1430 @@ +/** + ****************************************************************************** + * @file stm32f7308_discovery_audio.c + * @author MCD Application Team + * @brief This file provides the Audio driver for the STM32F7308-DISCOVERY + * board. + @verbatim + How To use this driver: + ----------------------- + + This driver supports STM32F7xx devices on STM32F7308-DISCOVERY (MB1260) Evaluation boards. + + Call the function BSP_AUDIO_OUT_Init( + OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, + OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH) + Volume : Initial volume to be set (0 is min (mute), 100 is max (100%) + AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...) + this parameter is relative to the audio file/stream type. + ) + This function configures all the hardware required for the audio application (codec, I2C, SAI, + GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK. + If the returned value is different from AUDIO_OK or the function is stuck then the communication with + the codec has failed (try to un-plug the power or reset device in this case). + - OUTPUT_DEVICE_SPEAKER : only speaker will be set as output for the audio stream. + - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream. + - OUTPUT_DEVICE_BOTH : both Speaker and Headphone are used as outputs for the audio stream + at the same time. + + Call the function BSP_DISCOVERY_AUDIO_OUT_Play( + pBuffer: pointer to the audio data file address + Size : size of the buffer to be sent in Bytes + ) + to start playing (for the first time) from the audio file/stream. + + Call the function BSP_AUDIO_OUT_Pause() to pause playing + + Call the function BSP_AUDIO_OUT_Resume() to resume playing. + Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called + for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case). + Note. This function should be called only when the audio file is played or paused (not stopped). + + For each mode, you may need to implement the relative callback functions into your code. + The Callback functions are named AUDIO_OUT_XXX_CallBack() and only their prototypes are declared in + the stm32f7308_discovery_audio.h file. (refer to the example for more details on the callbacks implementations) + + To Stop playing, to modify the volume level, the frequency, the audio frame slot, + the device output mode the mute or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(), + AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetAudioFrameSlot(), BSP_AUDIO_OUT_SetOutputMode(), + BSP_AUDIO_OUT_SetMute() and BSP_AUDIO_OUT_Stop(). + + The driver API and the callback functions are at the end of the stm32f7308_discovery_audio.h file. + + + Call the function BSP_AUDIO_IN_Init( + InputDevice: physical input mode (INPUT_DEVICE_DIGITAL_MICROPHONE_1, + INPUT_DEVICE_DIGITAL_MICROPHONE_2, INPUT_DEVICE_DIGITAL_MIC1_MIC2 + or INPUT_DEVICE_INPUT_LINE_1) + Volume : Initial volume to be set (0 is min (mute), 100 is max (100%) + AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000...) + this parameter is relative to the audio file/stream type. + ) + This function configures all the hardware required for the AUDIO IN application (SAI blocks, + SAI clock source, GPIOs, DMA and interrupt if needed). + This function returns AUDIO_OK if configuration is OK.If the returned value is different from AUDIO_OK then + the configuration should be wrong. + Note: On STM32F7308-DISCOVERY, two SAI blocks are configured and their DMA streams are configured + in CIRCULAR mode. + + Call the function BSP_AUDIO_IN_RECORD( + pBuf: pointer to the recorded audio data file address + Size: size of the buffer to be written in Bytes + ) + to start recording from microphones. + + + Call the function BSP_AUDIO_IN_Pause() to pause recording + + Call the function BSP_AUDIO_IN_Resume() to recording playing. + Note. After calling BSP_AUDIO_IN_Pause() function for pause, only BSP_AUDIO_IN_Resume() should be called + for resume (it is not allowed to call BSP_AUDIO_IN_RECORD() in this case). + + Call the function BSP_AUDIO_IN_Stop() to stop recording + + For each mode, you may need to implement the relative callback functions into your code. + The Callback functions are named BSP_AUDIO_IN_XXX_CallBack() and only their prototypes are declared in + the stm32f7308_discovery_audio.h file. (refer to the example for more details on the callbacks implementations) + + + Call the function BSP_AUDIO_IN_OUT_Init( + InputDevice : physical input mode (INPUT_DEVICE_DIGITAL_MICROPHONE_1, + INPUT_DEVICE_DIGITAL_MICROPHONE_2, INPUT_DEVICE_DIGITAL_MIC1_MIC2 + or INPUT_DEVICE_INPUT_LINE_1) + OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, + OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH) + Volume : Initial volume to be set (0 is min (mute), 100 is max (100%) + AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...) + this parameter is relative to the audio file/stream type. + ) + This function configures all the hardware required for the AUDIO IN(record) and AUDIO OUT(play) + application (SAI blocks, SAI clock source, GPIOs, DMA and interrupt if needed). + + Driver architecture: + -------------------- + + This driver provides the High Audio Layer: consists of the function API exported in the stm32f7308_discovery_audio.h file + (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...) + + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/ + providing the audio file/stream. These functions are also included as local functions into + the stm32f7308_discovery_audio.c file (SAIx_Out_Init() and SAIx_Out_DeInit(), SAIx_In_Init() and SAIx_In_DeInit()) + + Known Limitations: + ------------------ + 1- If the TDM Format used to play in parallel 2 audio Stream (the first Stream is configured in codec SLOT0 and second + Stream in SLOT1) the Pause/Resume, volume and mute feature will control the both streams. + 2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, + File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file. + 3- Supports only Stereo audio streaming. + 4- Supports only 16-bits audio data size. + @endverbatim + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7308_discovery.c +- stm32f7xx_hal_sai.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- wm8994.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7308_discovery_audio.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO STM32F7308_DISCOVERY_AUDIO + * @brief This file includes the low layer driver for wm8994 Audio Codec + * available on STM32F7308-DISCOVERY discoveryuation board(MB1260). + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO_Private_Types STM32F7308_DISCOVERY_AUDIO Private Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO_Private_Defines STM32F7308_DISCOVERY_AUDIO Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO_Private_Macros STM32F7308_DISCOVERY_AUDIO Private Macros + * @{ + */ + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO_Private_Variables STM32F7308_DISCOVERY_AUDIO Private Variables + * @{ + */ +AUDIO_DrvTypeDef *audio_drv; +SAI_HandleTypeDef haudio_out_sai; +SAI_HandleTypeDef haudio_in_sai; + +uint16_t __IO AudioInVolume = DEFAULT_AUDIO_IN_VOLUME; +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO_Private_Function_Prototypes STM32F7308_DISCOVERY_AUDIO Private Function Prototypes + * @{ + */ +static void SAIx_Out_Init(uint32_t AudioFreq); +static void SAIx_Out_DeInit(void); +static void SAIx_In_Init(uint32_t SaiOutMode, uint32_t SlotActive, uint32_t AudioFreq); +static void SAIx_In_DeInit(void); + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO_out_Private_Functions STM32F7308_DISCOVERY_AUDIO_Out Private Functions + * @{ + */ + +/** + * @brief Configures the audio out peripheral(SAI2 BlockA). + * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * or OUTPUT_DEVICE_BOTH. + * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) + * @param AudioFreq: Audio frequency used to play the audio stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + + /* Disable SAI */ + SAIx_Out_DeInit(); + + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); + } + SAIx_Out_Init(AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq); + } + + return ret; +} + +/** + * @brief Starts playing audio stream from a data buffer for a determined size. + * @param pBuffer: Pointer to the buffer + * @param Size: Number of audio data BYTES. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size) +{ + /* Call the audio Codec Play function */ + if(audio_drv->Play(AUDIO_I2C_ADDRESS, pBuffer, Size) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Update the Media layer and enable it for play */ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, DMA_MAX(Size / AUDIODATA_SIZE)); + + return AUDIO_OK; + } +} + +/** + * @brief This function Pauses the audio file stream. In case + * of using DMA, the DMA Pause feature is used. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Pause(void) +{ + /* Call the Audio Codec Pause/Resume function */ + if(audio_drv->Pause(AUDIO_I2C_ADDRESS) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause function */ + HAL_SAI_DMAPause(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief This function Resumes the audio file stream. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Resume(void) +{ + /* Call the Audio Codec Pause/Resume function */ + if(audio_drv->Resume(AUDIO_I2C_ADDRESS) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause/resume function */ + HAL_SAI_DMAResume(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Stops audio playing and Power down the Audio Codec. + * @param Option: could be one of the following parameters + * - CODEC_PDWN_SW: for software power off (by writing registers). + * Then no need to reconfigure the Codec after power on. + * - CODEC_PDWN_HW: completely shut down the codec (physically). + * Then need to reconfigure the Codec after power on. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option) +{ + /* Call the Media layer stop function */ + HAL_SAI_DMAStop(&haudio_out_sai); + + /* Call Audio Codec Stop function */ + if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) + { + return AUDIO_ERROR; + } + else + { + if(Option == CODEC_PDWN_HW) + { + /* Wait at least 100us */ + HAL_Delay(1); + } + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Controls the current audio volume level. + * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for + * Mute and 100 for Max volume level). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume) +{ + /* Call the codec volume control function with converted volume value */ + if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Enables or disables the MUTE mode by software + * @param Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to + * unmute the codec and restore previous volume level. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd) +{ + /* Call the Codec Mute function */ + if(audio_drv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Switch dynamically (while audio file is played) the output target + * (speaker or headphone). + * @param Output: The audio output target: OUTPUT_DEVICE_SPEAKER, + * OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output) +{ + /* Call the Codec output device function */ + if(audio_drv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Updates the audio frequency. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frequency. + * @retval None + */ +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq) +{ + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frequency configuration */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Updates the Audio frame slot configuration. + * @param AudioFrameSlot: specifies the audio Frame slot + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frame slot. + * @retval None + */ +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot) +{ + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frame slot configuration */ + haudio_out_sai.SlotInit.SlotActive = AudioFrameSlot; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Send n-Bytes on the SAI interface. + * @param pData: pointer on data address + * @param Size: number of data to be written + * @retval None + */ +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size) +{ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pData, Size); +} + +/** + * @brief Deinit the audio peripherals. + * @retval None + */ +void BSP_AUDIO_OUT_DeInit(void) +{ + SAIx_Out_DeInit(); + /* DeInit the SAI MSP : this __weak function can be rewritten by the application */ + BSP_AUDIO_OUT_MspDeInit(&haudio_out_sai, NULL); +} + +/** + * @brief Tx Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f7308_discovery_audio.h) */ + BSP_AUDIO_OUT_TransferComplete_CallBack(); +} + +/** + * @brief Tx Half Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f7308_discovery_audio.h) */ + BSP_AUDIO_OUT_HalfTransfer_CallBack(); +} + +/** + * @brief SAI error callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai) +{ + BSP_AUDIO_OUT_Error_CallBack(); +} + +/** + * @brief Manages the DMA full Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void) +{ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void) +{ +} + +/** + * @brief Manages the DMA FIFO error event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_Error_CallBack(void) +{ +} + +/** + * @brief Initializes BSP_AUDIO_OUT MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params) +{ + static DMA_HandleTypeDef hdma_sai_tx; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SAI clock */ + AUDIO_OUT_SAIx_CLK_ENABLE(); + + /* Enable GPIO clock */ + AUDIO_OUT_SAIx_MCLK_ENABLE(); + AUDIO_OUT_SAIx_SD_FS_CLK_ENABLE(); + + /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/ + gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN | AUDIO_OUT_SAIx_SCK_PIN | AUDIO_OUT_SAIx_SD_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_OUT_SAIx_AF; + HAL_GPIO_Init(AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN; + HAL_GPIO_Init(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, &gpio_init_structure); + + /* Enable the DMA clock */ + AUDIO_OUT_SAIx_DMAx_CLK_ENABLE(); + + if(hsai->Instance == AUDIO_OUT_SAIx) + { + /* Configure the hdma_saiTx handle parameters */ + hdma_sai_tx.Init.Channel = AUDIO_OUT_SAIx_DMAx_CHANNEL; + hdma_sai_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_sai_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sai_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sai_tx.Init.PeriphDataAlignment = AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE; + hdma_sai_tx.Init.MemDataAlignment = AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE; + hdma_sai_tx.Init.Mode = DMA_CIRCULAR; + hdma_sai_tx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_sai_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + hdma_sai_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sai_tx.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_sai_tx.Init.PeriphBurst = DMA_PBURST_SINGLE; + + hdma_sai_tx.Instance = AUDIO_OUT_SAIx_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsai, hdmatx, hdma_sai_tx); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_tx); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hdma_sai_tx); + } + + /* SAI DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_OUT_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ); +} + +/** + * @brief Deinitializes SAI MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* SAI DMA IRQ Channel deactivation */ + HAL_NVIC_DisableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ); + + if(hsai->Instance == AUDIO_OUT_SAIx) + { + /* Deinitialize the DMA stream */ + HAL_DMA_DeInit(hsai->hdmatx); + } + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(hsai); + + /* Deactivates CODEC_SAI pins FS, SCK, MCK and SD by putting them in input mode */ + gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN | AUDIO_OUT_SAIx_SCK_PIN | AUDIO_OUT_SAIx_SCK_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, gpio_init_structure.Pin); + + /* Disable SAI clock */ + AUDIO_OUT_SAIx_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the applic + by surcharging this __weak function */ +} + +/** + * @brief Clock Config. + * @param hsai: might be required to set audio peripheral predivider if any. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @param Params + * @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params) +{ + RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; + + HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); + + /* Set the PLL configuration according to the audio frequency */ + if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) + { + /* Configure PLLSAI prescalers */ + /* PLLSAI_VCO: VCO_429M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 429/2 = 214.5 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 214.5/19 = 11.289 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 429; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 2; + rcc_ex_clk_init_struct.PLLI2SDivQ = 19; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + + } + else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */ + { + /* SAI clock config + PLLSAI_VCO: VCO_344M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 344/7 = 49.142 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 49.142/1 = 49.142 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 344; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 7; + rcc_ex_clk_init_struct.PLLI2SDivQ = 1; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + } +} + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Initializes the Audio Codec audio interface (SAI). + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @note The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123 + * and user can update this configuration using + * @retval None + */ +static void SAIx_Out_Init(uint32_t AudioFreq) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_out_sai.Init.MonoStereoMode = SAI_STEREOMODE; + haudio_out_sai.Init.AudioFrequency = AudioFreq; + haudio_out_sai.Init.AudioMode = SAI_MODEMASTER_TX; + haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLED; + haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE; + haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; + haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; + haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + haudio_out_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; + haudio_out_sai.Init.CompandingMode = SAI_NOCOMPANDING; + haudio_out_sai.Init.TriState = SAI_OUTPUT_NOTRELEASED; + haudio_out_sai.Init.Mckdiv = 0; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_out_sai.FrameInit.FrameLength = 64; + haudio_out_sai.FrameInit.ActiveFrameLength = 32; + haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot actives */ + haudio_out_sai.SlotInit.FirstBitOffset = 0; + haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_out_sai.SlotInit.SlotNumber = 4; + haudio_out_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_0123; + + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Deinitializes the Audio Codec audio interface (SAI). + * @retval None + */ +static void SAIx_Out_DeInit(void) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + HAL_SAI_DeInit(&haudio_out_sai); +} + + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO_In_Private_Functions STM32F7308_DISCOVERY_AUDIO_In Private Functions + * @{ + */ + +/** + * @brief Initializes wave recording. + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @param BitRes: Audio frequency to be configured. + * @param ChnlNbr: Channel number. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + return BSP_AUDIO_IN_InitEx(INPUT_DEVICE_DIGITAL_MIC1_MIC2, AudioFreq, BitRes, ChnlNbr); +} + +/** + * @brief Initializes wave recording. + * @param InputDevice: INPUT_DEVICE_DIGITAL_MICROPHONE_1, INPUT_DEVICE_DIGITAL_MICROPHONE_2 + * INPUT_DEVICE_INPUT_LINE_1 or INPUT_DEVICE_DIGITAL_MIC1_MIC2 + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @param BitRes: Audio frequency to be configured. + * @param ChnlNbr: Channel number. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + uint32_t slot_active; + + /* Only INPUT_LINE_1, MICROPHONE_1, MICROPHONE_2 and MIC1&MIC2 inputs supported */ + if ((InputDevice != INPUT_DEVICE_INPUT_LINE_1) && + (InputDevice != INPUT_DEVICE_DIGITAL_MICROPHONE_1) && + (InputDevice != INPUT_DEVICE_DIGITAL_MICROPHONE_2) && + (InputDevice != INPUT_DEVICE_DIGITAL_MIC1_MIC2)) + { + ret = AUDIO_ERROR; + } + else + { + /* Disable SAI */ + SAIx_In_DeInit(); + + /* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_IN_ClockConfig(&haudio_in_sai, AudioFreq, NULL); /* Clock config is shared between AUDIO IN and OUT */ + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from SAI peripheral to memory */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + if(HAL_SAI_GetState(&haudio_in_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_in_sai, NULL); /* Initialize GPIOs for SAI2 block A Master signals */ + BSP_AUDIO_IN_MspInit(&haudio_in_sai, NULL); + } + + /* Configure SAI in master RX mode : + * - SAI2_block_A in master RX mode + * - SAI2_block_B in slave RX mode synchronous from SAI2_block_A + */ + if (InputDevice == INPUT_DEVICE_DIGITAL_MICROPHONE_2) + { + slot_active = CODEC_AUDIOFRAME_SLOT_13; + } + else if (InputDevice == INPUT_DEVICE_DIGITAL_MIC1_MIC2) + { + slot_active = CODEC_AUDIOFRAME_SLOT_0123; + } + else + { + slot_active = CODEC_AUDIOFRAME_SLOT_02; + } + SAIx_In_Init(SAI_MODEMASTER_RX, slot_active, AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, InputDevice, 100, AudioFreq); + } + } + return ret; +} + +/** + * @brief Initializes wave recording and playback in parallel. + * @param InputDevice: INPUT_DEVICE_DIGITAL_MICROPHONE_1, INPUT_DEVICE_DIGITAL_MICROPHONE_2 + * or INPUT_DEVICE_DIGITAL_MIC1_MIC2 + * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * or OUTPUT_DEVICE_BOTH. + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @param BitRes: Audio frequency to be configured. + * @param ChnlNbr: Channel number. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_OUT_Init(uint16_t InputDevice, uint16_t OutputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + uint32_t slot_active; + + if ((InputDevice != INPUT_DEVICE_DIGITAL_MICROPHONE_1) && + (InputDevice != INPUT_DEVICE_DIGITAL_MICROPHONE_2) && + (InputDevice != INPUT_DEVICE_DIGITAL_MIC1_MIC2)) + { + ret = AUDIO_ERROR; + } + else + { + /* Disable SAI */ + SAIx_In_DeInit(); + SAIx_Out_DeInit(); + + /* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_in_sai, AudioFreq, NULL); /* Clock config is shared between AUDIO IN and OUT */ + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from SAI peripheral to memory */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + if(HAL_SAI_GetState(&haudio_in_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_IN_MspInit(&haudio_in_sai, NULL); + } + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); + } + + /* Configure SAI in master mode : + * - SAI2_block_A in master TX mode + * - SAI2_block_B in slave RX mode synchronous from SAI2_block_A + */ + if (InputDevice == INPUT_DEVICE_DIGITAL_MICROPHONE_2) + { + slot_active = CODEC_AUDIOFRAME_SLOT_13; + } + else if (InputDevice == INPUT_DEVICE_DIGITAL_MIC1_MIC2) + { + slot_active = CODEC_AUDIOFRAME_SLOT_0123; + } + else + { + slot_active = CODEC_AUDIOFRAME_SLOT_02; + } + SAIx_In_Init(SAI_MODEMASTER_TX, slot_active, AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, InputDevice | OutputDevice, 100, AudioFreq); + } + } + return ret; +} + +/** + * @brief Starts audio recording. + * @param pbuf: Main buffer pointer for the recorded data storing + * @param size: size of the recorded buffer in number of elements (typically number of half-words) + * Be careful that it is not the same unit than BSP_AUDIO_OUT_Play function + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size) +{ + uint32_t ret = AUDIO_ERROR; + + /* Start the process receive DMA */ + if(HAL_SAI_Receive_DMA(&haudio_in_sai, (uint8_t*)pbuf, size) == HAL_OK) + { + /* Return AUDIO_OK when all operations are correctly done */ + ret = AUDIO_OK; + } + + return ret; +} + +/** + * @brief Stops audio recording. + * @param Option: could be one of the following parameters + * - CODEC_PDWN_SW: for software power off (by writing registers). + * Then no need to reconfigure the Codec after power on. + * - CODEC_PDWN_HW: completely shut down the codec (physically). + * Then need to reconfigure the Codec after power on. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Stop(uint32_t Option) +{ + /* Call the Media layer stop function */ + HAL_SAI_DMAStop(&haudio_in_sai); + + /* Call Audio Codec Stop function */ + if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) + { + return AUDIO_ERROR; + } + else + { + if(Option == CODEC_PDWN_HW) + { + /* Wait at least 100us */ + HAL_Delay(1); + } + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Pauses the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Pause(void) +{ + /* Call the Media layer pause function */ + HAL_SAI_DMAPause(&haudio_in_sai); + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Resumes the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Resume(void) +{ + /* Call the Media layer pause/resume function */ + HAL_SAI_DMAResume(&haudio_in_sai); + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Controls the audio in volume level. + * @param Volume: Volume level in range 0(Mute)..80(+0dB)..100(+17.625dB) + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume) +{ + /* Call the codec volume control function with converted volume value */ + if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Set the Global variable AudioInVolume */ + AudioInVolume = Volume; + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Deinit the audio IN peripherals. + * @retval None + */ +void BSP_AUDIO_IN_DeInit(void) +{ + SAIx_In_DeInit(); + /* DeInit the SAI MSP : this __weak function can be rewritten by the application */ + BSP_AUDIO_IN_MspDeInit(&haudio_in_sai, NULL); +} + + /** + * @brief Rx Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ + BSP_AUDIO_IN_TransferComplete_CallBack(); +} + +/** + * @brief Rx Half Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f7308_discovery_audio.h) */ + BSP_AUDIO_IN_HalfTransfer_CallBack(); +} + +/** + * @brief User callback when record buffer is filled. + * @retval None + */ +__weak void BSP_AUDIO_IN_TransferComplete_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Audio IN Error callback function. + * @retval None + */ +__weak void BSP_AUDIO_IN_Error_CallBack(void) +{ + /* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +} + +/** + * @brief Initializes BSP_AUDIO_IN MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_IN_MspInit(SAI_HandleTypeDef *hsai, void *Params) +{ + static DMA_HandleTypeDef hdma_sai_rx; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SAI clock */ + AUDIO_IN_SAIx_CLK_ENABLE(); + + /* Enable SD GPIO clock */ + AUDIO_IN_SAIx_SD_ENABLE(); + /* CODEC_SAI pin configuration: SD pin */ + gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = AUDIO_IN_SAIx_SD_AF; + HAL_GPIO_Init(AUDIO_IN_SAIx_SD_GPIO_PORT, &gpio_init_structure); + + /* Enable Audio INT GPIO clock */ + AUDIO_IN_INT_GPIO_ENABLE(); + /* Audio INT pin configuration: input */ + gpio_init_structure.Pin = AUDIO_IN_INT_GPIO_PIN; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + HAL_GPIO_Init(AUDIO_IN_INT_GPIO_PORT, &gpio_init_structure); + + /* Enable the DMA clock */ + AUDIO_IN_SAIx_DMAx_CLK_ENABLE(); + + if(hsai->Instance == AUDIO_IN_SAIx) + { + /* Configure the hdma_sai_rx handle parameters */ + hdma_sai_rx.Init.Channel = AUDIO_IN_SAIx_DMAx_CHANNEL; + hdma_sai_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_sai_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sai_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sai_rx.Init.PeriphDataAlignment = AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE; + hdma_sai_rx.Init.MemDataAlignment = AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE; + hdma_sai_rx.Init.Mode = DMA_CIRCULAR; + hdma_sai_rx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_sai_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_sai_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sai_rx.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_sai_rx.Init.PeriphBurst = DMA_MBURST_SINGLE; + + hdma_sai_rx.Instance = AUDIO_IN_SAIx_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsai, hdmarx, hdma_sai_rx); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_rx); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hdma_sai_rx); + } + + /* SAI DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_IN_SAIx_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_IN_SAIx_DMAx_IRQ); + + /* Audio INT IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_IN_INT_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_IN_INT_IRQ); +} + +/** + * @brief DeInitializes BSP_AUDIO_IN MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_IN_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* SAI IN DMA IRQ Channel deactivation */ + HAL_NVIC_DisableIRQ(AUDIO_IN_SAIx_DMAx_IRQ); + + if(hsai->Instance == AUDIO_IN_SAIx) + { + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(haudio_in_sai.hdmarx); + } + + /* Disable SAI block */ + __HAL_SAI_DISABLE(hsai); + + /* Disable pin: SD pin */ + gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN; + HAL_GPIO_DeInit(AUDIO_IN_SAIx_SD_GPIO_PORT, gpio_init_structure.Pin); + + /* Disable SAI clock */ + AUDIO_IN_SAIx_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Clock Config. + * @param hsai: might be required to set audio peripheral predivider if any. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @param Params + * @note This API is called by BSP_AUDIO_IN_Init() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_AUDIO_IN_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params) +{ + RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; + + HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); + + /* Set the PLL configuration according to the audio frequency */ + if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) + { + /* Configure PLLSAI prescalers */ + /* PLLSAI_VCO: VCO_429M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 429/2 = 214.5 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 214.5/19 = 11.289 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 429; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 2; + rcc_ex_clk_init_struct.PLLI2SDivQ = 19; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + + } + else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K), AUDIO_FREQUENCY_96K */ + { + /* SAI clock config + PLLSAI_VCO: VCO_344M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 344/7 = 49.142 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 49.142/1 = 49.142 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 344; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 7; + rcc_ex_clk_init_struct.PLLI2SDivQ = 1; + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + } +} + +/******************************************************************************* + Static Functions +*******************************************************************************/ +/** + * @brief Initializes the input Audio Codec audio interface (SAI). + * @param SaiOutMode: SAI_MODEMASTER_TX (for record and playback in parallel) + * or SAI_MODEMASTER_RX (for record only). + * @param SlotActive: CODEC_AUDIOFRAME_SLOT_02, CODEC_AUDIOFRAME_SLOT_13 or + * CODEC_AUDIOFRAME_SLOT_0123 + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @retval None + */ +static void SAIx_In_Init(uint32_t SaiOutMode, uint32_t SlotActive, uint32_t AudioFreq) +{ + /* Initialize the haudio_out_sai instance parameters */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + haudio_out_sai.Init.AudioMode = SaiOutMode; + haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; + haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE; + haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; + haudio_out_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; + haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; + haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + haudio_out_sai.Init.Mckdiv = 0; + haudio_out_sai.Init.MonoStereoMode = SAI_STEREOMODE; + haudio_out_sai.Init.CompandingMode = SAI_NOCOMPANDING; + haudio_out_sai.Init.TriState = SAI_OUTPUT_NOTRELEASED; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_out_sai.FrameInit.FrameLength = 64; + haudio_out_sai.FrameInit.ActiveFrameLength = 32; + haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot actives */ + haudio_out_sai.SlotInit.FirstBitOffset = 0; + haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_out_sai.SlotInit.SlotNumber = 4; + haudio_out_sai.SlotInit.SlotActive = SlotActive; + + HAL_SAI_Init(&haudio_out_sai); + + /* Initialize SAI2 block B in SLAVE RX synchronous from SAI2 block A */ + /* Initialize the haudio_in_sai instance parameters */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_in_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_in_sai.Init.AudioFrequency = AudioFreq; + haudio_in_sai.Init.AudioMode = SAI_MODESLAVE_RX; + haudio_in_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; + haudio_in_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_in_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_in_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_in_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; + haudio_in_sai.Init.Synchro = SAI_SYNCHRONOUS; + haudio_in_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; + haudio_in_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; + haudio_in_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + haudio_in_sai.Init.Mckdiv = 0; + haudio_in_sai.Init.MonoStereoMode = SAI_STEREOMODE; + haudio_in_sai.Init.CompandingMode = SAI_NOCOMPANDING; + haudio_in_sai.Init.TriState = SAI_OUTPUT_NOTRELEASED; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_in_sai.FrameInit.FrameLength = 64; + haudio_in_sai.FrameInit.ActiveFrameLength = 32; + haudio_in_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_in_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_in_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot active */ + haudio_in_sai.SlotInit.FirstBitOffset = 0; + haudio_in_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_in_sai.SlotInit.SlotNumber = 4; + haudio_in_sai.SlotInit.SlotActive = SlotActive; + + HAL_SAI_Init(&haudio_in_sai); + + /* Enable SAI peripheral */ + __HAL_SAI_ENABLE(&haudio_in_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + + + +/** + * @brief Deinitializes the output Audio Codec audio interface (SAI). + * @retval None + */ +static void SAIx_In_DeInit(void) +{ + /* Initialize the haudio_in_sai Instance parameter */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(&haudio_in_sai); + + HAL_SAI_DeInit(&haudio_in_sai); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_audio.h b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_audio.h new file mode 100644 index 00000000..27c3b3d6 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_audio.h @@ -0,0 +1,304 @@ +/** + ****************************************************************************** + * @file stm32f7308_discovery_audio.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f7308_discovery_audio.c driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7308_DISCOVERY_AUDIO_H +#define __STM32F7308_DISCOVERY_AUDIO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include audio component Driver */ +#include "../Components/wm8994/wm8994.h" +#include "stm32f7308_discovery.h" +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO STM32F7308_DISCOVERY_AUDIO + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO_Exported_Types STM32F7308_DISCOVERY_AUDIO Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO_Exported_Constants STM32F7308_DISCOVERY_AUDIO Exported Constants + * @{ + */ + +/** @defgroup BSP_Audio_Out_Option BSP Audio Out Option + * @{ + */ +#define BSP_AUDIO_OUT_CIRCULARMODE ((uint32_t)0x00000001) /* BUFFER CIRCULAR MODE */ +#define BSP_AUDIO_OUT_NORMALMODE ((uint32_t)0x00000002) /* BUFFER NORMAL MODE */ +#define BSP_AUDIO_OUT_STEREOMODE ((uint32_t)0x00000004) /* STEREO MODE */ +#define BSP_AUDIO_OUT_MONOMODE ((uint32_t)0x00000008) /* MONO MODE */ +/** + * @} + */ +/** @defgroup BSP_Audio_Sample_Rate BSP Audio Sample Rate + * @{ + */ +#define BSP_AUDIO_FREQUENCY_96K SAI_AUDIO_FREQUENCY_96K +#define BSP_AUDIO_FREQUENCY_48K SAI_AUDIO_FREQUENCY_48K +#define BSP_AUDIO_FREQUENCY_44K SAI_AUDIO_FREQUENCY_44K +#define BSP_AUDIO_FREQUENCY_32K SAI_AUDIO_FREQUENCY_32K +#define BSP_AUDIO_FREQUENCY_22K SAI_AUDIO_FREQUENCY_22K +#define BSP_AUDIO_FREQUENCY_16K SAI_AUDIO_FREQUENCY_16K +#define BSP_AUDIO_FREQUENCY_11K SAI_AUDIO_FREQUENCY_11K +#define BSP_AUDIO_FREQUENCY_8K SAI_AUDIO_FREQUENCY_8K +/** + * @} + */ + +/*------------------------------------------------------------------------------ + USER SAI defines parameters + -----------------------------------------------------------------------------*/ +/** CODEC_AudioFrame_SLOT_TDMMode In W8994 codec the Audio frame contains 4 slots : TDM Mode + * TDM format : + * +------------------|------------------|--------------------|-------------------+ + * | CODEC_SLOT0 Left | CODEC_SLOT1 Left | CODEC_SLOT0 Right | CODEC_SLOT1 Right | + * +------------------------------------------------------------------------------+ + */ +/* To have 2 separate audio stream in Both headphone and speaker the 4 slot must be activated */ +#define CODEC_AUDIOFRAME_SLOT_0123 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_2 | SAI_SLOTACTIVE_3 + +/* To have an audio stream in headphone only SAI Slot 0 and Slot 2 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_02 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_2 +/* To have an audio stream in speaker only SAI Slot 1 and Slot 3 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_13 SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_3 + + +/* SAI peripheral configuration defines */ +#define AUDIO_OUT_SAIx SAI2_Block_A +#define AUDIO_OUT_SAIx_CLK_ENABLE() __HAL_RCC_SAI2_CLK_ENABLE() +#define AUDIO_OUT_SAIx_CLK_DISABLE() __HAL_RCC_SAI2_CLK_DISABLE() +#define AUDIO_OUT_SAIx_AF GPIO_AF10_SAI2 + +#define AUDIO_OUT_SAIx_MCLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define AUDIO_OUT_SAIx_MCLK_GPIO_PORT GPIOI +#define AUDIO_OUT_SAIx_MCLK_PIN GPIO_PIN_4 +#define AUDIO_OUT_SAIx_SD_FS_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT GPIOI +#define AUDIO_OUT_SAIx_FS_PIN GPIO_PIN_7 +#define AUDIO_OUT_SAIx_SCK_PIN GPIO_PIN_5 +#define AUDIO_OUT_SAIx_SD_PIN GPIO_PIN_6 + +/* SAI DMA Stream definitions */ +#define AUDIO_OUT_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_OUT_SAIx_DMAx_STREAM DMA2_Stream4 +#define AUDIO_OUT_SAIx_DMAx_CHANNEL DMA_CHANNEL_3 +#define AUDIO_OUT_SAIx_DMAx_IRQ DMA2_Stream4_IRQn +#define AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD +#define AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD +#define DMA_MAX_SZE 0xFFFF + +#define AUDIO_OUT_SAIx_DMAx_IRQHandler DMA2_Stream4_IRQHandler + +/* Select the interrupt preemption priority for the DMA interrupt */ +#define AUDIO_OUT_IRQ_PREPRIO ((uint32_t)0x0E) /* Select the preemption priority level(0 is the highest) */ + +/*------------------------------------------------------------------------------ + AUDIO IN CONFIGURATION +------------------------------------------------------------------------------*/ +/* SAI IN peripheral configuration defines */ +#define AUDIO_IN_SAIx SAI2_Block_B +#define AUDIO_IN_SAIx_CLK_ENABLE() __HAL_RCC_SAI2_CLK_ENABLE() +#define AUDIO_IN_SAIx_CLK_DISABLE() __HAL_RCC_SAI2_CLK_DISABLE() +#define AUDIO_IN_SAIx_SD_AF GPIO_AF10_SAI2 + +#define AUDIO_IN_SAIx_SD_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE() +#define AUDIO_IN_SAIx_SD_GPIO_PORT GPIOG +#define AUDIO_IN_SAIx_SD_PIN GPIO_PIN_10 + +#define AUDIO_IN_INT_GPIO_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE() +#define AUDIO_IN_INT_GPIO_PORT GPIOG +#define AUDIO_IN_INT_GPIO_PIN GPIO_PIN_15 +#define AUDIO_IN_INT_IRQ EXTI15_10_IRQn + +/* SAI DMA Stream definitions */ +#define AUDIO_IN_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_IN_SAIx_DMAx_STREAM DMA2_Stream6 +#define AUDIO_IN_SAIx_DMAx_CHANNEL DMA_CHANNEL_3 +#define AUDIO_IN_SAIx_DMAx_IRQ DMA2_Stream6_IRQn +#define AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD +#define AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD + +#define AUDIO_IN_SAIx_DMAx_IRQHandler DMA2_Stream6_IRQHandler +#define AUDIO_IN_INT_IRQHandler EXTI15_10_IRQHandler + +/* Select the interrupt preemption priority and subpriority for the IT/DMA interrupt */ +#define AUDIO_IN_IRQ_PREPRIO ((uint32_t)0x0F) /* Select the preemption priority level(0 is the highest) */ + + +/*------------------------------------------------------------------------------ + CONFIGURATION: Audio Driver Configuration parameters +------------------------------------------------------------------------------*/ + +#define AUDIODATA_SIZE 2 /* 16-bits audio data size */ + +/* Audio status definition */ +#define AUDIO_OK ((uint8_t)0) +#define AUDIO_ERROR ((uint8_t)1) +#define AUDIO_TIMEOUT ((uint8_t)2) + +/* AudioFreq * DataSize (2 bytes) * NumChannels (Stereo: 2) */ +#define DEFAULT_AUDIO_IN_FREQ BSP_AUDIO_FREQUENCY_16K +#define DEFAULT_AUDIO_IN_BIT_RESOLUTION ((uint8_t)16) +#define DEFAULT_AUDIO_IN_CHANNEL_NBR ((uint8_t)2) /* Mono = 1, Stereo = 2 */ +#define DEFAULT_AUDIO_IN_VOLUME ((uint16_t)64) + +/*------------------------------------------------------------------------------ + OPTIONAL Configuration defines parameters +------------------------------------------------------------------------------*/ + +/* Delay for the Codec to be correctly reset */ +#define CODEC_RESET_DELAY ((uint8_t)5) + + +/*------------------------------------------------------------------------------ + OUTPUT DEVICES definition +------------------------------------------------------------------------------*/ +/* Alias on existing output devices to adapt to headphones output */ +#define OUTPUT_DEVICE_HEADPHONE1 OUTPUT_DEVICE_HEADPHONE +#define OUTPUT_DEVICE_HEADPHONE2 OUTPUT_DEVICE_SPEAKER + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO_Exported_Variables STM32F7308_DISCOVERY_AUDIO Exported Variables + * @{ + */ + /** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO_Exported_Macros STM32F7308_DISCOVERY_AUDIO Exported Macros + * @{ + */ +#define DMA_MAX(x) (((x) <= DMA_MAX_SZE)? (x):DMA_MAX_SZE) +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO_OUT_Exported_Functions STM32F7308_DISCOVERY_AUDIO_OUT Exported Functions + * @{ + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq); +void BSP_AUDIO_OUT_DeInit(void); +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size); +uint8_t BSP_AUDIO_OUT_Pause(void); +uint8_t BSP_AUDIO_OUT_Resume(void); +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option); +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume); +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq); +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot); +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd); +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output); +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size); + +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function is called when the requested data has been completely transferred.*/ +void BSP_AUDIO_OUT_TransferComplete_CallBack(void); + +/* This function is called when half of the requested buffer has been transferred. */ +void BSP_AUDIO_OUT_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_OUT_Error_CallBack(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params); +void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params); +void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_AUDIO_IN_Exported_Functions STM32F7308_DISCOVERY_AUDIO_IN Exported Functions + * @{ + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_OUT_Init(uint16_t InputDevice, uint16_t OutputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +void BSP_AUDIO_IN_DeInit(void); +uint8_t BSP_AUDIO_IN_Record(uint16_t *pData, uint32_t Size); +uint8_t BSP_AUDIO_IN_Stop(uint32_t Option); +uint8_t BSP_AUDIO_IN_Pause(void); +uint8_t BSP_AUDIO_IN_Resume(void); +uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume); +void BSP_AUDIO_IN_DeInit(void); + +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled to prepare the next + buffer pointer and its size. */ +void BSP_AUDIO_IN_TransferComplete_CallBack(void); +void BSP_AUDIO_IN_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_IN_Error_CallBack(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_IN_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params); +void BSP_AUDIO_IN_MspInit(SAI_HandleTypeDef *hsai, void *Params); +void BSP_AUDIO_IN_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7308_DISCOVERY_AUDIO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_lcd.c b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_lcd.c new file mode 100644 index 00000000..03c265b7 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_lcd.c @@ -0,0 +1,1166 @@ +/** + ****************************************************************************** + * @file stm32f7308_discovery_lcd.c + * @author MCD Application Team + * @brief This file includes the driver for Liquid Crystal Display (LCD) module + * mounted on STM32F7308-DISCOVERY board. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + + +/* File Info : ----------------------------------------------------------------- + User NOTES +1. How To use this driver: +-------------------------- + - This driver is used to drive indirectly an LCD TFT. + - This driver supports the ST7789H2 LCD. + - The ST7789H2 component driver MUST be included with this driver. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the LCD using the BSP_LCD_Init() function. + + + Display on LCD + o Clear the hole LCD using BSP_LCD_Clear() function or only one specified string + line using the BSP_LCD_ClearStringLine() function. + o Display a character on the specified line and column using the BSP_LCD_DisplayChar() + function or a complete string line using the BSP_LCD_DisplayStringAtLine() function. + o Display a string line on the specified position (x,y in pixel) and align mode + using the BSP_LCD_DisplayStringAtLine() function. + o Draw and fill a basic shapes (dot, line, rectangle, circle, ellipse, .. bitmap) + on LCD using the available set of functions. + +------------------------------------------------------------------------------*/ + +/* Dependencies +- stm32f7308_discovery.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_sram.c +- stm32f7xx_hal_rcc_ex.h +- st7789h2.c +- fonts.h +- font24.c +- font20.c +- font16.c +- font12.c +- font8.c" +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7308_discovery_lcd.h" +#include "../../../Utilities/Fonts/fonts.h" +#include "../../../Utilities/Fonts/font24.c" +#include "../../../Utilities/Fonts/font20.c" +#include "../../../Utilities/Fonts/font16.c" +#include "../../../Utilities/Fonts/font12.c" +#include "../../../Utilities/Fonts/font8.c" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_LCD STM32F7308_DISCOVERY_LCD + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_LCD_Private_TypesDefinitions STM32F7308 Discovery Lcd Private TypesDef + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LCD_Private_Defines STM32F7308 Discovery Lcd Private Defines + * @{ + */ +#define POLY_X(Z) ((int32_t)((Points + Z)->X)) +#define POLY_Y(Z) ((int32_t)((Points + Z)->Y)) +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LCD_Private_Macros STM32F7308 Discovery Lcd Private Macros + * @{ + */ +#define ABS(X) ((X) > 0 ? (X) : -(X)) +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LCD_Private_Variables STM32F7308 Discovery Lcd Private Variables + * @{ + */ +LCD_DrawPropTypeDef DrawProp; +static LCD_DrvTypeDef *LcdDrv; + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LCD_Private_FunctionPrototypes STM32F7308 Discovery Lcd Private Prototypes + * @{ + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c); +static void SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3); +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LCD_Private_Functions STM32F7308 Discovery Lcd Private Functions + * @{ + */ +/** + * @brief Initializes the LCD. + * @retval LCD state + */ +uint8_t BSP_LCD_Init(void) +{ + return (BSP_LCD_InitEx(LCD_ORIENTATION_LANDSCAPE)); +} +/** + * @brief Initializes the LCD with a given orientation. + * @param orientation: LCD_ORIENTATION_PORTRAIT or LCD_ORIENTATION_LANDSCAPE + * @retval LCD state + */ +uint8_t BSP_LCD_InitEx(uint32_t orientation) +{ + uint8_t ret = LCD_ERROR; + + /* Default value for draw propriety */ + DrawProp.BackColor = 0xFFFF; + DrawProp.pFont = &Font24; + DrawProp.TextColor = 0x0000; + + /* Initialize LCD special pins GPIOs */ + BSP_LCD_MspInit(); + + /* Backlight control signal assertion */ + HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_PORT, LCD_BL_CTRL_PIN, GPIO_PIN_SET); + + /* Apply hardware reset according to procedure indicated in FRD154BP2901 documentation */ + HAL_GPIO_WritePin(LCD_RESET_GPIO_PORT, LCD_RESET_PIN, GPIO_PIN_RESET); + HAL_Delay(5); /* Reset signal asserted during 5ms */ + HAL_GPIO_WritePin(LCD_RESET_GPIO_PORT, LCD_RESET_PIN, GPIO_PIN_SET); + HAL_Delay(10); /* Reset signal released during 10ms */ + HAL_GPIO_WritePin(LCD_RESET_GPIO_PORT, LCD_RESET_PIN, GPIO_PIN_RESET); + HAL_Delay(20); /* Reset signal asserted during 20ms */ + HAL_GPIO_WritePin(LCD_RESET_GPIO_PORT, LCD_RESET_PIN, GPIO_PIN_SET); + HAL_Delay(10); /* Reset signal released during 10ms */ + + if(ST7789H2_drv.ReadID() == ST7789H2_ID) + { + LcdDrv = &ST7789H2_drv; + + /* LCD Init */ + LcdDrv->Init(); + + if(orientation == LCD_ORIENTATION_PORTRAIT) + { + ST7789H2_SetOrientation(LCD_ORIENTATION_PORTRAIT); + } + else if(orientation == LCD_ORIENTATION_LANDSCAPE_ROT180) + { + ST7789H2_SetOrientation(LCD_ORIENTATION_LANDSCAPE_ROT180); + } + else + { + /* Default landscape orientation is selected */ + } + /* Initialize the font */ + BSP_LCD_SetFont(&LCD_DEFAULT_FONT); + + ret = LCD_OK; + } + + return ret; +} + +/** + * @brief DeInitializes the LCD. + * @retval LCD state + */ +uint8_t BSP_LCD_DeInit(void) +{ + /* Actually LcdDrv does not provide a DeInit function */ + return LCD_OK; +} + +/** + * @brief Gets the LCD X size. + * @retval Used LCD X size + */ +uint32_t BSP_LCD_GetXSize(void) +{ + return(LcdDrv->GetLcdPixelWidth()); +} + +/** + * @brief Gets the LCD Y size. + * @retval Used LCD Y size + */ +uint32_t BSP_LCD_GetYSize(void) +{ + return(LcdDrv->GetLcdPixelHeight()); +} + +/** + * @brief Gets the LCD text color. + * @retval Used text color. + */ +uint16_t BSP_LCD_GetTextColor(void) +{ + return DrawProp.TextColor; +} + +/** + * @brief Gets the LCD background color. + * @retval Used background color + */ +uint16_t BSP_LCD_GetBackColor(void) +{ + return DrawProp.BackColor; +} + +/** + * @brief Sets the LCD text color. + * @param Color: Text color code RGB(5-6-5) + * @retval None + */ +void BSP_LCD_SetTextColor(uint16_t Color) +{ + DrawProp.TextColor = Color; +} + +/** + * @brief Sets the LCD background color. + * @param Color: Background color code RGB(5-6-5) + * @retval None + */ +void BSP_LCD_SetBackColor(uint16_t Color) +{ + DrawProp.BackColor = Color; +} + +/** + * @brief Sets the LCD text font. + * @param fonts: Font to be used + * @retval None + */ +void BSP_LCD_SetFont(sFONT *fonts) +{ + DrawProp.pFont = fonts; +} + +/** + * @brief Gets the LCD text font. + * @retval Used font + */ +sFONT *BSP_LCD_GetFont(void) +{ + return DrawProp.pFont; +} + +/** + * @brief Clears the hole LCD. + * @param Color: Color of the background + * @retval None + */ +void BSP_LCD_Clear(uint16_t Color) +{ + uint32_t counter = 0; + uint32_t y_size = 0; + uint32_t color_backup = DrawProp.TextColor; + + DrawProp.TextColor = Color; + y_size = BSP_LCD_GetYSize(); + + for(counter = 0; counter < y_size; counter++) + { + BSP_LCD_DrawHLine(0, counter, BSP_LCD_GetXSize()); + } + DrawProp.TextColor = color_backup; + BSP_LCD_SetTextColor(DrawProp.TextColor); +} + +/** + * @brief Clears the selected line. + * @param Line: Line to be cleared + * This parameter can be one of the following values: + * @arg 0..9: if the Current fonts is Font16x24 + * @arg 0..19: if the Current fonts is Font12x12 or Font8x12 + * @arg 0..29: if the Current fonts is Font8x8 + * @retval None + */ +void BSP_LCD_ClearStringLine(uint16_t Line) +{ + uint32_t color_backup = DrawProp.TextColor; + + DrawProp.TextColor = DrawProp.BackColor; + + /* Draw a rectangle with background color */ + BSP_LCD_FillRect(0, (Line * DrawProp.pFont->Height), BSP_LCD_GetXSize(), DrawProp.pFont->Height); + + DrawProp.TextColor = color_backup; + BSP_LCD_SetTextColor(DrawProp.TextColor); +} + +/** + * @brief Displays one character. + * @param Xpos: Start column address + * @param Ypos: Line where to display the character shape. + * @param Ascii: Character ascii code + * This parameter must be a number between Min_Data = 0x20 and Max_Data = 0x7E + * @retval None + */ +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii) +{ + DrawChar(Xpos, Ypos, &DrawProp.pFont->table[(Ascii-' ') *\ + DrawProp.pFont->Height * ((DrawProp.pFont->Width + 7) / 8)]); +} + +/** + * @brief Displays characters on the LCD. + * @param Xpos: X position (in pixel) + * @param Ypos: Y position (in pixel) + * @param Text: Pointer to string to display on LCD + * @param Mode: Display mode + * This parameter can be one of the following values: + * @arg CENTER_MODE + * @arg RIGHT_MODE + * @arg LEFT_MODE + * @retval None + */ +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Line_ModeTypdef Mode) +{ + uint16_t refcolumn = 1, i = 0; + uint32_t size = 0, xsize = 0; + uint8_t *ptr = Text; + + /* Get the text size */ + while (*ptr++) size ++ ; + + /* Characters number per line */ + xsize = (BSP_LCD_GetXSize()/DrawProp.pFont->Width); + + switch (Mode) + { + case CENTER_MODE: + { + refcolumn = Xpos + ((xsize - size)* DrawProp.pFont->Width) / 2; + break; + } + case LEFT_MODE: + { + refcolumn = Xpos; + break; + } + case RIGHT_MODE: + { + refcolumn = - Xpos + ((xsize - size)*DrawProp.pFont->Width); + break; + } + default: + { + refcolumn = Xpos; + break; + } + } + + /* Check that the Start column is located in the screen */ + if ((refcolumn < 1) || (refcolumn >= 0x8000)) + { + refcolumn = 1; + } + + /* Send the string character by character on lCD */ + while ((*Text != 0) & (((BSP_LCD_GetXSize() - (i*DrawProp.pFont->Width)) & 0xFFFF) >= DrawProp.pFont->Width)) + { + /* Display one character on LCD */ + BSP_LCD_DisplayChar(refcolumn, Ypos, *Text); + /* Decrement the column position by 16 */ + refcolumn += DrawProp.pFont->Width; + /* Point on the next character */ + Text++; + i++; + } +} + +/** + * @brief Displays a character on the LCD. + * @param Line: Line where to display the character shape + * This parameter can be one of the following values: + * @arg 0..9: if the Current fonts is Font16x24 + * @arg 0..19: if the Current fonts is Font12x12 or Font8x12 + * @arg 0..29: if the Current fonts is Font8x8 + * @param ptr: Pointer to string to display on LCD + * @retval None + */ +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr) +{ + BSP_LCD_DisplayStringAt(0, LINE(Line), ptr, LEFT_MODE); +} + +/** + * @brief Reads an LCD pixel. + * @param Xpos: X position + * @param Ypos: Y position + * @retval RGB pixel color + */ +uint16_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos) +{ + uint16_t ret = 0; + + if(LcdDrv->ReadPixel != NULL) + { + ret = LcdDrv->ReadPixel(Xpos, Ypos); + } + + return ret; +} + +/** + * @brief Draws a pixel on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param RGB_Code: Pixel color in RGB mode (5-6-5) + * @retval None + */ +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGB_Code) +{ + if(LcdDrv->WritePixel != NULL) + { + LcdDrv->WritePixel(Xpos, Ypos, RGB_Code); + } +} + +/** + * @brief Draws an horizontal line. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + * @retval None + */ +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t index = 0; + + if(LcdDrv->DrawHLine != NULL) + { + LcdDrv->DrawHLine(DrawProp.TextColor, Xpos, Ypos, Length); + } + else + { + for(index = 0; index < Length; index++) + { + BSP_LCD_DrawPixel((Xpos + index), Ypos, DrawProp.TextColor); + } + } +} + +/** + * @brief Draws a vertical line. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + * @retval None + */ +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t index = 0; + + if(LcdDrv->DrawVLine != NULL) + { + LcdDrv->DrawVLine(DrawProp.TextColor, Xpos, Ypos, Length); + } + else + { + for(index = 0; index < Length; index++) + { + BSP_LCD_DrawPixel(Xpos, Ypos + index, DrawProp.TextColor); + } + } +} + +/** + * @brief Draws an uni-line (between two points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @retval None + */ +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + numadd = deltay; + numpixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + numadd = deltax; + numpixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= numpixels; curpixel++) + { + BSP_LCD_DrawPixel(x, y, DrawProp.TextColor); /* Draw the current pixel */ + num += numadd; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Draws a rectangle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + * @retval None + */ +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Draw horizontal lines */ + BSP_LCD_DrawHLine(Xpos, Ypos, Width); + BSP_LCD_DrawHLine(Xpos, (Ypos+ Height), Width); + + /* Draw vertical lines */ + BSP_LCD_DrawVLine(Xpos, Ypos, Height); + BSP_LCD_DrawVLine((Xpos + Width), Ypos, Height); +} + +/** + * @brief Draws a circle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + * @retval None + */ +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t decision; /* Decision Variable */ + uint32_t current_x; /* Current X Value */ + uint32_t current_y; /* Current Y Value */ + + decision = 3 - (Radius << 1); + current_x = 0; + current_y = Radius; + + while (current_x <= current_y) + { + BSP_LCD_DrawPixel((Xpos + current_x), (Ypos - current_y), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos - current_x), (Ypos - current_y), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos + current_y), (Ypos - current_x), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos - current_y), (Ypos - current_x), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos + current_x), (Ypos + current_y), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos - current_x), (Ypos + current_y), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos + current_y), (Ypos + current_x), DrawProp.TextColor); + + BSP_LCD_DrawPixel((Xpos - current_y), (Ypos + current_x), DrawProp.TextColor); + + /* Initialize the font */ + BSP_LCD_SetFont(&LCD_DEFAULT_FONT); + + if (decision < 0) + { + decision += (current_x << 2) + 6; + } + else + { + decision += ((current_x - current_y) << 2) + 10; + current_y--; + } + current_x++; + } +} + +/** + * @brief Draws an poly-line (between many points). + * @param Points: Pointer to the points array + * @param PointCount: Number of points + * @retval None + */ +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t x = 0, y = 0; + + if(PointCount < 2) + { + return; + } + + BSP_LCD_DrawLine(Points->X, Points->Y, (Points+PointCount-1)->X, (Points+PointCount-1)->Y); + + while(--PointCount) + { + x = Points->X; + y = Points->Y; + Points++; + BSP_LCD_DrawLine(x, y, Points->X, Points->Y); + } +} + +/** + * @brief Draws an ellipse on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + * @retval None + */ +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float k = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + k = (float)(rad2/rad1); + + do { + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/k)), (Ypos+y), DrawProp.TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/k)), (Ypos+y), DrawProp.TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/k)), (Ypos-y), DrawProp.TextColor); + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/k)), (Ypos-y), DrawProp.TextColor); + + e2 = err; + if (e2 <= x) { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Draws a bitmap picture (16 bpp). + * @param Xpos: Bmp X position in the LCD + * @param Ypos: Bmp Y position in the LCD + * @param pbmp: Pointer to Bmp picture address. + * @retval None + */ +void BSP_LCD_DrawBitmap(uint16_t Xpos, uint16_t Ypos, uint8_t *pbmp) +{ + uint32_t height = 0; + uint32_t width = 0; + + /* Read bitmap width */ + width = pbmp[18] + (pbmp[19] << 8) + (pbmp[20] << 16) + (pbmp[21] << 24); + + /* Read bitmap height */ + height = pbmp[22] + (pbmp[23] << 8) + (pbmp[24] << 16) + (pbmp[25] << 24); + + SetDisplayWindow(Xpos, Ypos, width, height); + + if(LcdDrv->DrawBitmap != NULL) + { + LcdDrv->DrawBitmap(Xpos, Ypos, pbmp); + } + SetDisplayWindow(0, 0, BSP_LCD_GetXSize(), BSP_LCD_GetYSize()); +} + +/** + * @brief Draws RGB Image (16 bpp). + * @param Xpos: X position in the LCD + * @param Ypos: Y position in the LCD + * @param Xsize: X size in the LCD + * @param Ysize: Y size in the LCD + * @param pdata: Pointer to the RGB Image address. + * @retval None + */ +void BSP_LCD_DrawRGBImage(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint16_t Ysize, uint8_t *pdata) +{ + + SetDisplayWindow(Xpos, Ypos, Xsize, Ysize); + + if(LcdDrv->DrawRGBImage != NULL) + { + LcdDrv->DrawRGBImage(Xpos, Ypos, Xsize, Ysize, pdata); + } + SetDisplayWindow(0, 0, BSP_LCD_GetXSize(), BSP_LCD_GetYSize()); +} + +/** + * @brief Draws a full rectangle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + * @retval None + */ +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + BSP_LCD_SetTextColor(DrawProp.TextColor); + do + { + BSP_LCD_DrawHLine(Xpos, Ypos++, Width); + } + while(Height--); +} + +/** + * @brief Draws a full circle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + * @retval None + */ +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t decision; /* Decision Variable */ + uint32_t current_x; /* Current X Value */ + uint32_t current_y; /* Current Y Value */ + + decision = 3 - (Radius << 1); + + current_x = 0; + current_y = Radius; + + BSP_LCD_SetTextColor(DrawProp.TextColor); + + while (current_x <= current_y) + { + if(current_y > 0) + { + BSP_LCD_DrawHLine(Xpos - current_y, Ypos + current_x, 2*current_y); + BSP_LCD_DrawHLine(Xpos - current_y, Ypos - current_x, 2*current_y); + } + + if(current_x > 0) + { + BSP_LCD_DrawHLine(Xpos - current_x, Ypos - current_y, 2*current_x); + BSP_LCD_DrawHLine(Xpos - current_x, Ypos + current_y, 2*current_x); + } + if (decision < 0) + { + decision += (current_x << 2) + 6; + } + else + { + decision += ((current_x - current_y) << 2) + 10; + current_y--; + } + current_x++; + } + + BSP_LCD_SetTextColor(DrawProp.TextColor); + BSP_LCD_DrawCircle(Xpos, Ypos, Radius); +} + +/** + * @brief Draws a full poly-line (between many points). + * @param Points: Pointer to the points array + * @param PointCount: Number of points + * @retval None + */ +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t X = 0, Y = 0, X2 = 0, Y2 = 0, X_center = 0, Y_center = 0, X_first = 0, Y_first = 0, pixelX = 0, pixelY = 0, counter = 0; + uint16_t IMAGE_LEFT = 0, IMAGE_RIGHT = 0, IMAGE_TOP = 0, IMAGE_BOTTOM = 0; + + IMAGE_LEFT = IMAGE_RIGHT = Points->X; + IMAGE_TOP= IMAGE_BOTTOM = Points->Y; + + for(counter = 1; counter < PointCount; counter++) + { + pixelX = POLY_X(counter); + if(pixelX < IMAGE_LEFT) + { + IMAGE_LEFT = pixelX; + } + if(pixelX > IMAGE_RIGHT) + { + IMAGE_RIGHT = pixelX; + } + + pixelY = POLY_Y(counter); + if(pixelY < IMAGE_TOP) + { + IMAGE_TOP = pixelY; + } + if(pixelY > IMAGE_BOTTOM) + { + IMAGE_BOTTOM = pixelY; + } + } + + if(PointCount < 2) + { + return; + } + + X_center = (IMAGE_LEFT + IMAGE_RIGHT)/2; + Y_center = (IMAGE_BOTTOM + IMAGE_TOP)/2; + + X_first = Points->X; + Y_first = Points->Y; + + while(--PointCount) + { + X = Points->X; + Y = Points->Y; + Points++; + X2 = Points->X; + Y2 = Points->Y; + + FillTriangle(X, X2, X_center, Y, Y2, Y_center); + FillTriangle(X, X_center, X2, Y, Y_center, Y2); + FillTriangle(X_center, X2, X, Y_center, Y2, Y); + } + + FillTriangle(X_first, X2, X_center, Y_first, Y2, Y_center); + FillTriangle(X_first, X_center, X2, Y_first, Y_center, Y2); + FillTriangle(X_center, X2, X_first, Y_center, Y2, Y_first); +} + +/** + * @brief Draws a full ellipse. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + * @retval None + */ +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float k = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + k = (float)(rad2/rad1); + + do + { + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/k)), (Ypos+y), (2*(uint16_t)(x/k) + 1)); + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/k)), (Ypos-y), (2*(uint16_t)(x/k) + 1)); + + e2 = err; + if (e2 <= x) + { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Enables the display. + * @retval None + */ +void BSP_LCD_DisplayOn(void) +{ + LcdDrv->DisplayOn(); +} + +/** + * @brief Disables the display. + * @retval None + */ +void BSP_LCD_DisplayOff(void) +{ + LcdDrv->DisplayOff(); +} + + +/** + * @brief Initializes the LCD GPIO special pins MSP. + * @retval None + */ +__weak void BSP_LCD_MspInit(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable GPIOs clock */ + LCD_RESET_GPIO_CLK_ENABLE(); + LCD_TE_GPIO_CLK_ENABLE(); + LCD_BL_CTRL_GPIO_CLK_ENABLE(); + + /* LCD_RESET GPIO configuration */ + gpio_init_structure.Pin = LCD_RESET_PIN; /* LCD_RESET pin has to be manually controlled */ + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + HAL_GPIO_Init(LCD_RESET_GPIO_PORT, &gpio_init_structure); + HAL_GPIO_WritePin( LCD_RESET_GPIO_PORT, LCD_RESET_PIN, GPIO_PIN_RESET); + + /* LCD_TE GPIO configuration */ + gpio_init_structure.Pin = LCD_TE_PIN; /* LCD_TE pin has to be manually managed */ + gpio_init_structure.Mode = GPIO_MODE_INPUT; + HAL_GPIO_Init(LCD_TE_GPIO_PORT, &gpio_init_structure); + + /* LCD_BL_CTRL GPIO configuration */ + gpio_init_structure.Pin = LCD_BL_CTRL_PIN; /* LCD_BL_CTRL pin has to be manually controlled */ + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(LCD_BL_CTRL_GPIO_PORT, &gpio_init_structure); +} + +/** + * @brief DeInitializes LCD GPIO special pins MSP. + * @retval None + */ +__weak void BSP_LCD_MspDeInit(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* LCD_RESET GPIO deactivation */ + gpio_init_structure.Pin = LCD_RESET_PIN; + HAL_GPIO_DeInit(LCD_RESET_GPIO_PORT, gpio_init_structure.Pin); + + /* LCD_TE GPIO deactivation */ + gpio_init_structure.Pin = LCD_TE_PIN; + HAL_GPIO_DeInit(LCD_TE_GPIO_PORT, gpio_init_structure.Pin); + + /* LCD_BL_CTRL GPIO deactivation */ + gpio_init_structure.Pin = LCD_BL_CTRL_PIN; + HAL_GPIO_DeInit(LCD_BL_CTRL_GPIO_PORT, gpio_init_structure.Pin); + + /* GPIO pins clock can be shut down in the application + by surcharging this __weak function */ +} + +/****************************************************************************** + Static Functions +*******************************************************************************/ + +/** + * @brief Draws a character on LCD. + * @param Xpos: Line where to display the character shape + * @param Ypos: Start column address + * @param c: Pointer to the character data + * @retval None + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c) +{ + uint32_t i = 0, j = 0; + uint16_t height, width; + uint8_t offset; + uint8_t *pchar; + uint32_t line; + + height = DrawProp.pFont->Height; + width = DrawProp.pFont->Width; + + offset = 8 *((width + 7)/8) - width ; + + for(i = 0; i < height; i++) + { + pchar = ((uint8_t *)c + (width + 7)/8 * i); + + switch(((width + 7)/8)) + { + case 1: + line = pchar[0]; + break; + + case 2: + line = (pchar[0]<< 8) | pchar[1]; + break; + + case 3: + default: + line = (pchar[0]<< 16) | (pchar[1]<< 8) | pchar[2]; + break; + } + + for (j = 0; j < width; j++) + { + if(line & (1 << (width- j + offset- 1))) + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp.TextColor); + } + else + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp.BackColor); + } + } + Ypos++; + } +} + +/** + * @brief Sets display window. + * @param Xpos: LCD X position + * @param Ypos: LCD Y position + * @param Width: LCD window width + * @param Height: LCD window height + * @retval None + */ +static void SetDisplayWindow(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + if(LcdDrv->SetDisplayWindow != NULL) + { + LcdDrv->SetDisplayWindow(Xpos, Ypos, Width, Height); + } +} + +/** + * @brief Fills a triangle (between 3 points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @param x3: Point 3 X position + * @param y3: Point 3 Y position + * @retval None + */ +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + numadd = deltay; + numpixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + numadd = deltax; + numpixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= numpixels; curpixel++) + { + BSP_LCD_DrawLine(x, y, x3, y3); + + num += numadd; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_lcd.h b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_lcd.h new file mode 100644 index 00000000..7158d253 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_lcd.h @@ -0,0 +1,217 @@ +/** + ****************************************************************************** + * @file stm32f7308_discovery_lcd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f7308_discovery_lcd.c driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7308_DISCOVERY_LCD_H +#define __STM32F7308_DISCOVERY_LCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7308_discovery.h" +#include "../Components/st7789h2/st7789h2.h" +#include "../../../Utilities/Fonts/fonts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_LCD STM32F7308-DISCOVERY LCD + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_LCD_Exported_Types STM32F7308 DISCOVERY LCD Exported Types + * @{ + */ +typedef struct +{ + uint32_t TextColor; + uint32_t BackColor; + sFONT *pFont; +}LCD_DrawPropTypeDef; +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LCD_Exported_Constants STM32F7308 DISCOVERY LCD Exported Constants + * @{ + */ +/** + * @brief LCD status structure definition + */ +#define LCD_OK ((uint8_t)0x00) +#define LCD_ERROR ((uint8_t)0x01) +#define LCD_TIMEOUT ((uint8_t)0x02) + +typedef struct +{ + int16_t X; + int16_t Y; +}Point, * pPoint; + +/** + * @brief Line mode structures definition + */ +typedef enum +{ + CENTER_MODE = 0x01, /* Center mode */ + RIGHT_MODE = 0x02, /* Right mode */ + LEFT_MODE = 0x03 /* Left mode */ +}Line_ModeTypdef; + + +#define LCD_ORIENTATION_PORTRAIT ((uint8_t)0x00) /*!< Portrait orientation choice of LCD screen */ +#define LCD_ORIENTATION_LANDSCAPE ((uint8_t)0x01) /*!< Landscape orientation choice of LCD screen */ +#define LCD_ORIENTATION_LANDSCAPE_ROT180 ((uint32_t)0x02) /*!< Landscape rotated 180° orientation choice of LCD screen */ + + +/** + * @brief LCD color + */ +#define LCD_COLOR_BLUE ((uint16_t)0x001F) +#define LCD_COLOR_GREEN ((uint16_t)0x07E0) +#define LCD_COLOR_RED ((uint16_t)0xF800) +#define LCD_COLOR_CYAN ((uint16_t)0x07FF) +#define LCD_COLOR_MAGENTA ((uint16_t)0xF81F) +#define LCD_COLOR_YELLOW ((uint16_t)0xFFE0) +#define LCD_COLOR_LIGHTBLUE ((uint16_t)0x841F) +#define LCD_COLOR_LIGHTGREEN ((uint16_t)0x87F0) +#define LCD_COLOR_LIGHTRED ((uint16_t)0xFC10) +#define LCD_COLOR_LIGHTMAGENTA ((uint16_t)0xFC1F) +#define LCD_COLOR_LIGHTYELLOW ((uint16_t)0xFFF0) +#define LCD_COLOR_DARKBLUE ((uint16_t)0x0010) +#define LCD_COLOR_DARKGREEN ((uint16_t)0x0400) +#define LCD_COLOR_DARKRED ((uint16_t)0x8000) +#define LCD_COLOR_DARKCYAN ((uint16_t)0x0410) +#define LCD_COLOR_DARKMAGENTA ((uint16_t)0x8010) +#define LCD_COLOR_DARKYELLOW ((uint16_t)0x8400) +#define LCD_COLOR_WHITE ((uint16_t)0xFFFF) +#define LCD_COLOR_LIGHTGRAY ((uint16_t)0xD69A) +#define LCD_COLOR_GRAY ((uint16_t)0x8410) +#define LCD_COLOR_DARKGRAY ((uint16_t)0x4208) +#define LCD_COLOR_BLACK ((uint16_t)0x0000) +#define LCD_COLOR_BROWN ((uint16_t)0xA145) +#define LCD_COLOR_ORANGE ((uint16_t)0xFD20) + +/** + * @brief LCD default font + */ +#define LCD_DEFAULT_FONT Font12 + +/** + * @brief LCD special pins + */ +/* LCD reset pin */ +#define LCD_RESET_PIN GPIO_PIN_7 +#define LCD_RESET_GPIO_PORT GPIOH +#define LCD_RESET_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() +#define LCD_RESET_GPIO_CLK_DISABLE() __HAL_RCC_GPIOH_CLK_DISABLE() + +/* LCD tearing effect pin */ +#define LCD_TE_PIN GPIO_PIN_8 +#define LCD_TE_GPIO_PORT GPIOC +#define LCD_TE_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define LCD_TE_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE() + +/* Backlight control pin */ +#define LCD_BL_CTRL_PIN GPIO_PIN_11 +#define LCD_BL_CTRL_GPIO_PORT GPIOH +#define LCD_BL_CTRL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() +#define LCD_BL_CTRL_GPIO_CLK_DISABLE() __HAL_RCC_GPIOH_CLK_DISABLE() + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_LCD_Exported_Functions STM32F7308 DISCOVERY LCD Exported Functions + * @{ + */ +uint8_t BSP_LCD_Init(void); +uint8_t BSP_LCD_InitEx(uint32_t orientation); +uint8_t BSP_LCD_DeInit(void); +uint32_t BSP_LCD_GetXSize(void); +uint32_t BSP_LCD_GetYSize(void); + +uint16_t BSP_LCD_GetTextColor(void); +uint16_t BSP_LCD_GetBackColor(void); +void BSP_LCD_SetTextColor(__IO uint16_t Color); +void BSP_LCD_SetBackColor(__IO uint16_t Color); +void BSP_LCD_SetFont(sFONT *fonts); +sFONT *BSP_LCD_GetFont(void); + +void BSP_LCD_Clear(uint16_t Color); +void BSP_LCD_ClearStringLine(uint16_t Line); +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr); +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Line_ModeTypdef Mode); +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii); + +uint16_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos); +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint16_t RGB_Code); +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius); +void BSP_LCD_DrawBitmap(uint16_t Xpos, uint16_t Ypos, uint8_t *pbmp); +void BSP_LCD_DrawRGBImage(uint16_t Xpos, uint16_t Ypos, uint16_t Xsize, uint16_t Ysize, uint8_t *pbmp); +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius); + +void BSP_LCD_DisplayOff(void); +void BSP_LCD_DisplayOn(void); + +/* These functions can be modified in case the current settings + need to be changed for specific application needs */ +__weak void BSP_LCD_MspInit(void); +__weak void BSP_LCD_MspDeInit(void); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7308_DISCOVERY_LCD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_psram.c b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_psram.c new file mode 100644 index 00000000..e6afe9dc --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_psram.c @@ -0,0 +1,387 @@ +/** + ****************************************************************************** + * @file stm32f7308_discovery_psram.c + * @author MCD Application Team + * @brief This file includes the PSRAM driver for the IS61WV51216BLL-10MLI memory + * device mounted on STM32F7308-DISCOVERY boards. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the IS61WV51216BLL-10M PSRAM external memory mounted + on STM32F7308 discovery board. + - This driver does not need a specific component driver for the PSRAM device + to be included with. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the PSRAM external memory using the BSP_PSRAM_Init() function. This + function includes the MSP layer hardware resources initialization and the + FMC controller configuration to interface with the external PSRAM memory. + + + PSRAM read/write operations + o PSRAM external memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_PSRAM_ReadData()/BSP_PSRAM_WriteData(), or by DMA transfer using the functions + BSP_PSRAM_ReadData_DMA()/BSP_PSRAM_WriteData_DMA(). + o The AHB access is performed with 16-bit width transaction, the DMA transfer + configuration is fixed at single (no burst) halfword transfer + (see the PSRAM_MspInit() static function). + o User can implement his own functions for read/write access with his desired + configurations. + o If interrupt mode is used for DMA transfer, the function BSP_PSRAM_DMA_IRQHandler() + is called in IRQ handler file, to serve the generated interrupt once the DMA + transfer is complete. + @endverbatim + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_sram.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7308_discovery_psram.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_PSRAM STM32F7308_DISCOVERY_PSRAM + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_PSRAM_Private_Types_Definitions PSRAM Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_PSRAM_Private_Defines PSRAM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_PSRAM_Private_Macros PSRAM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_PSRAM_Private_Variables PSRAM Private Variables + * @{ + */ +SRAM_HandleTypeDef psramHandle; + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_PSRAM_Private_Function_Prototypes PSRAM Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_PSRAM_Private_Functions PSRAM Private Functions + * @{ + */ + +/** + * @brief Initializes the PSRAM device. + * @retval PSRAM status + */ +uint8_t BSP_PSRAM_Init(void) +{ + static FMC_NORSRAM_TimingTypeDef Timing; + static uint8_t psram_status = PSRAM_ERROR; + + /* PSRAM device configuration */ + psramHandle.Instance = FMC_NORSRAM_DEVICE; + psramHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + /* PSRAM device configuration */ + /* Timing configuration derived from system clock (up to 216Mhz) + for 108Mhz as PSRAM clock frequency */ + Timing.AddressSetupTime = 9; + Timing.AddressHoldTime = 2; + Timing.DataSetupTime = 6; + Timing.BusTurnAroundDuration = 1; + Timing.CLKDivision = 2; + Timing.DataLatency = 2; + Timing.AccessMode = FMC_ACCESS_MODE_A; + + psramHandle.Init.NSBank = FMC_NORSRAM_BANK1; + psramHandle.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; + psramHandle.Init.MemoryType = FMC_MEMORY_TYPE_SRAM; + psramHandle.Init.MemoryDataWidth = PSRAM_MEMORY_WIDTH; + psramHandle.Init.BurstAccessMode = PSRAM_BURSTACCESS; + psramHandle.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; + psramHandle.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; + psramHandle.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; + psramHandle.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE; + psramHandle.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; + psramHandle.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE; + psramHandle.Init.WriteBurst = PSRAM_WRITEBURST; + psramHandle.Init.WriteFifo = FMC_WRITE_FIFO_DISABLE; + psramHandle.Init.PageSize = FMC_PAGE_SIZE_NONE; + psramHandle.Init.ContinuousClock = CONTINUOUSCLOCK_FEATURE; + + /* PSRAM controller initialization */ + BSP_PSRAM_MspInit(&psramHandle, NULL); /* __weak function can be rewritten by the application */ + if(HAL_SRAM_Init(&psramHandle, &Timing, &Timing) != HAL_OK) + { + psram_status = PSRAM_ERROR; + } + else + { + psram_status = PSRAM_OK; + } + return psram_status; +} + +/** + * @brief DeInitializes the PSRAM device. + * @retval PSRAM status + */ +uint8_t BSP_PSRAM_DeInit(void) +{ + static uint8_t psram_status = PSRAM_ERROR; + /* PSRAM device de-initialization */ + psramHandle.Instance = FMC_NORSRAM_DEVICE; + psramHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + if(HAL_SRAM_DeInit(&psramHandle) != HAL_OK) + { + psram_status = PSRAM_ERROR; + } + else + { + psram_status = PSRAM_OK; + } + + /* PSRAM controller de-initialization */ + BSP_PSRAM_MspDeInit(&psramHandle, NULL); + + return psram_status; +} + +/** + * @brief Reads an amount of data from the PSRAM device in polling mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval PSRAM status + */ +uint8_t BSP_PSRAM_ReadData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Read_16b(&psramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return PSRAM_ERROR; + } + else + { + return PSRAM_OK; + } +} + +/** + * @brief Reads an amount of data from the PSRAM device in DMA mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval PSRAM status + */ +uint8_t BSP_PSRAM_ReadData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Read_DMA(&psramHandle, (uint32_t *)uwStartAddress, (uint32_t *)pData, uwDataSize) != HAL_OK) + { + return PSRAM_ERROR; + } + else + { + return PSRAM_OK; + } +} + +/** + * @brief Writes an amount of data from the PSRAM device in polling mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval PSRAM status + */ +uint8_t BSP_PSRAM_WriteData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Write_16b(&psramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return PSRAM_ERROR; + } + else + { + return PSRAM_OK; + } +} + +/** + * @brief Writes an amount of data from the PSRAM device in DMA mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval PSRAM status + */ +uint8_t BSP_PSRAM_WriteData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Write_DMA(&psramHandle, (uint32_t *)uwStartAddress, (uint32_t *)pData, uwDataSize) != HAL_OK) + { + return PSRAM_ERROR; + } + else + { + return PSRAM_OK; + } +} + +/** + * @brief Initializes PSRAM MSP. + * @param hsram: PSRAM handle + * @param Params + * @retval None + */ +__weak void BSP_PSRAM_MspInit(SRAM_HandleTypeDef *hsram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable FMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + + /* Enable chosen DMAx clock */ + __PSRAM_DMAx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF12_FMC; + + /* GPIOD configuration: GPIO_PIN_7 is FMC_NE1 , GPIO_PIN_11 ans GPIO_PIN_12 are PSRAM_A16 and PSRAM_A17 */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7 | GPIO_PIN_8 |\ + GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_14 | GPIO_PIN_15; + + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOE configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 |\ + GPIO_PIN_12 |GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOF configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOF, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + /* Configure common DMA parameters */ + dma_handle.Init.Channel = PSRAM_DMAx_CHANNEL; + dma_handle.Init.Direction = DMA_MEMORY_TO_MEMORY; + dma_handle.Init.PeriphInc = DMA_PINC_ENABLE; + dma_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + dma_handle.Init.Mode = DMA_NORMAL; + dma_handle.Init.Priority = DMA_PRIORITY_HIGH; + dma_handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + dma_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_handle.Init.MemBurst = DMA_MBURST_SINGLE; + dma_handle.Init.PeriphBurst = DMA_PBURST_SINGLE; + + dma_handle.Instance = PSRAM_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsram, hdma, dma_handle); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&dma_handle); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&dma_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(PSRAM_DMAx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(PSRAM_DMAx_IRQn); +} + + +/** + * @brief DeInitializes SRAM MSP. + * @param hsram: SRAM handle + * @param Params + * @retval None + */ +__weak void BSP_PSRAM_MspDeInit(SRAM_HandleTypeDef *hsram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + + /* Disable NVIC configuration for DMA interrupt */ + HAL_NVIC_DisableIRQ(PSRAM_DMAx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_handle.Instance = PSRAM_DMAx_STREAM; + HAL_DMA_DeInit(&dma_handle); + + /* GPIO pins clock, FMC clock and DMA clock can be shut down in the applications + by surcharging this __weak function */ +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_psram.h b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_psram.h new file mode 100644 index 00000000..6cc57778 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_psram.h @@ -0,0 +1,124 @@ +/** + ****************************************************************************** + * @file stm32f7308_discovery_psram.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f7308_discovery_psram.c driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7308_DISCOVERY_PSRAM_H +#define __STM32F7308_DISCOVERY_PSRAM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY_PSRAM + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_PSRAM_Exported_Types PSRAM Exported Types + * @{ + */ + +/** + * @brief PSRAM status structure definition + */ +#define PSRAM_OK ((uint8_t)0x00) +#define PSRAM_ERROR ((uint8_t)0x01) + +#define PSRAM_DEVICE_ADDR ((uint32_t)0x60000000) +#define PSRAM_DEVICE_SIZE ((uint32_t)0x80000) /* SRAM device size in Bytes */ + +/* #define SRAM_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_8*/ +#define PSRAM_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_16 + +#define PSRAM_BURSTACCESS FMC_BURST_ACCESS_MODE_DISABLE +/* #define PSRAM_BURSTACCESS FMC_BURST_ACCESS_MODE_ENABLE*/ + +#define PSRAM_WRITEBURST FMC_WRITE_BURST_DISABLE +/* #define PSRAM_WRITEBURST FMC_WRITE_BURST_ENABLE */ + +#define CONTINUOUSCLOCK_FEATURE FMC_CONTINUOUS_CLOCK_SYNC_ONLY +/* #define CONTINUOUSCLOCK_FEATURE FMC_CONTINUOUS_CLOCK_SYNC_ASYNC */ + +/* DMA definitions for SRAM DMA transfer */ +#define __PSRAM_DMAx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define __PSRAM_DMAx_CLK_DISABLE __HAL_RCC_DMA2_CLK_DISABLE +#define PSRAM_DMAx_CHANNEL DMA_CHANNEL_0 +#define PSRAM_DMAx_STREAM DMA2_Stream5 +#define PSRAM_DMAx_IRQn DMA2_Stream5_IRQn +#define BSP_PSRAM_DMA_IRQHandler DMA2_Stream5_IRQHandler + +/** @defgroup STM32F7308_DISCOVERY_PSRAM_Exported_Macro PSRAM Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_PSRAM_Exported_Functions PSRAM Exported Functions + * @{ + */ +uint8_t BSP_PSRAM_Init(void); +uint8_t BSP_PSRAM_DeInit(void); +uint8_t BSP_PSRAM_ReadData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_PSRAM_ReadData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_PSRAM_WriteData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_PSRAM_WriteData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_PSRAM_MspInit(SRAM_HandleTypeDef *hsram, void *Params); +void BSP_PSRAM_MspDeInit(SRAM_HandleTypeDef *hsram, void *Params); +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7308_DISCOVERY_PSRAM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_qspi.c b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_qspi.c new file mode 100644 index 00000000..7d5429fa --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_qspi.c @@ -0,0 +1,1166 @@ +/** + ****************************************************************************** + * @file stm32f7308_discovery_qspi.c + * @author MCD Application Team + * @brief This file includes a standard driver for the MX25L512 QSPI + * memory mounted on STM32F7308-Discovery board. + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + (#) This driver is used to drive the MX25L512 QSPI external + memory mounted on STM32F7308-Discovery board. + + (#) This driver need a specific component driver (MX25L51245G) to be included with. + + (#) Initialization steps: + (++) Initialize the QPSI external memory using the BSP_QSPI_Init() function. This + function includes the MSP layer hardware resources initialization and the + QSPI interface with the external memory. + + (#) QSPI memory operations + (++) QSPI memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_QSPI_Read()/BSP_QSPI_Write(). + (++) The function BSP_QSPI_GetInfo() returns the configuration of the QSPI memory. + (see the QSPI memory data sheet) + (++) Perform erase block operation using the function BSP_QSPI_Erase_Block() and by + specifying the block address. You can perform an erase operation of the whole + chip by calling the function BSP_QSPI_Erase_Chip(). + (++) The function BSP_QSPI_GetStatus() returns the current status of the QSPI memory. + (see the QSPI memory data sheet) + @endverbatim + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_qspi.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- mx25l512.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7308_discovery_qspi.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_QSPI STM32F7308_DISCOVERY_QSPI + * @{ + */ + + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup STM32F7308_DISCOVERY_QSPI_Private_Variables STM32F7308_DISCOVERY QSPI Private Variables + * @{ + */ +QSPI_HandleTypeDef QSPIHandle; + +/** + * @} + */ + + + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup STM32F7308_DISCOVERY_QSPI_Private_Functions STM32F7308_DISCOVERY QSPI Private Functions + * @{ + */ +static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_EnterMemory_QPI(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_ExitMemory_QPI(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_OutDrvStrengthCfg(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_AutoPollingMemReady (QSPI_HandleTypeDef *hqspi, uint32_t Timeout); + +/** + * @} + */ + +/** @defgroup STM32F7308_DISCOVERY_QSPI_Exported_Functions STM32F7308_DISCOVERY QSPI Exported Functions + * @{ + */ + +/** + * @brief Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Init(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level initialization */ + BSP_QSPI_MspInit(&QSPIHandle, NULL); + + /* QSPI initialization */ + /* QSPI freq = SYSCLK /(1 + ClockPrescaler) = 216 MHz/(1+1) = 108 Mhz */ + QSPIHandle.Init.ClockPrescaler = 1; /* QSPI freq = 216 MHz/(1+1) = 108 Mhz */ + QSPIHandle.Init.FifoThreshold = 16; + QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; + QSPIHandle.Init.FlashSize = POSITION_VAL(MX25L512_FLASH_SIZE) - 1; + QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_4_CYCLE; /* Min 30ns for nonRead */ + QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; + QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1; + QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE; + + if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* QSPI memory reset */ + if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Put QSPI memory in QPI mode */ + if( QSPI_EnterMemory_QPI( &QSPIHandle )!=QSPI_OK ) + { + return QSPI_NOT_SUPPORTED; + } + + /* Set the QSPI memory in 4-bytes address mode */ + if (QSPI_EnterFourBytesAddress(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Configuration of the dummy cycles on QSPI memory side */ + if (QSPI_DummyCyclesCfg(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Configuration of the Output driver strength on memory side */ + if( QSPI_OutDrvStrengthCfg( &QSPIHandle ) != QSPI_OK ) + { + return QSPI_NOT_SUPPORTED; + } + + return QSPI_OK; +} + +/** + * @brief De-Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_DeInit(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Put QSPI memory in SPI mode */ + if( QSPI_ExitMemory_QPI(&QSPIHandle )!=QSPI_OK ) + { + return QSPI_NOT_SUPPORTED; + } + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level De-initialization */ + BSP_QSPI_MspDeInit(&QSPIHandle, NULL); + + return QSPI_OK; +} + +/** + * @brief Reads an amount of data from the QSPI memory. + * @param pData: Pointer to data to be read + * @param ReadAddr: Read start address + * @param Size: Size of data to read + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the read command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = QSPI_READ_4_BYTE_ADDR_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.Address = ReadAddr; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = MX25L512_DUMMY_CYCLES_READ_QUAD_IO; + s_command.NbData = Size; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Set S# timing for Read command */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_1_CYCLE); + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Restore S# timing for nonRead commands */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_4_CYCLE); + + return QSPI_OK; +} + +/** + * @brief Writes an amount of data to the QSPI memory. + * @param pData: Pointer to data to be written + * @param WriteAddr: Write start address + * @param Size: Size of data to write + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + uint32_t end_addr, current_size, current_addr; + + /* Calculation of the size between the write address and the end of the page */ + current_size = MX25L512_PAGE_SIZE - (WriteAddr % MX25L512_PAGE_SIZE); + + /* Check if the size of the data is less than the remaining place in the page */ + if (current_size > Size) + { + current_size = Size; + } + + /* Initialize the address variables */ + current_addr = WriteAddr; + end_addr = WriteAddr + Size; + + /* Initialize the program command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = QSPI_PAGE_PROG_4_BYTE_ADDR_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Perform the write page by page */ + do + { + s_command.Address = current_addr; + s_command.NbData = current_size; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of program */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update the address and size variables for next page programming */ + current_addr += current_size; + pData += current_size; + current_size = ((current_addr + MX25L512_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : MX25L512_PAGE_SIZE; + } while (current_addr < end_addr); + + return QSPI_OK; +} + +/** + * @brief Erases the specified block of the QSPI memory. + * @param BlockAddress: Block address to erase + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = SUBSECTOR_ERASE_4_BYTE_ADDR_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.Address = BlockAddress; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, MX25L512_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Erases the entire QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Chip(void) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = BULK_ERASE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, MX25L512_BULK_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Reads current status of the QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetStatus(void) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg; + + /* Initialize the read flag status register command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Check the value of the register*/ + if ((reg & MX25L512_SR_WIP) == 0) + { + return QSPI_OK; + } + else + { + return QSPI_BUSY; + } +} + +/** + * @brief Return the configuration of the QSPI memory. + * @param pInfo: pointer on the configuration structure + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetInfo(QSPI_Info* pInfo) +{ + /* Configure the structure with the memory configuration */ + pInfo->FlashSize = MX25L512_FLASH_SIZE; + pInfo->EraseSectorSize = MX25L512_SUBSECTOR_SIZE; + pInfo->EraseSectorsNumber = (MX25L512_FLASH_SIZE/MX25L512_SUBSECTOR_SIZE); + pInfo->ProgPageSize = MX25L512_PAGE_SIZE; + pInfo->ProgPagesNumber = (MX25L512_FLASH_SIZE/MX25L512_PAGE_SIZE); + + return QSPI_OK; +} + +/** + * @brief Configure the QSPI in memory-mapped mode + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_EnableMemoryMappedMode(void) +{ + QSPI_CommandTypeDef s_command; + QSPI_MemoryMappedTypeDef s_mem_mapped_cfg; + + /* Configure the command for the read instruction */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = QSPI_READ_4_BYTE_ADDR_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = MX25L512_DUMMY_CYCLES_READ_QUAD_IO; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the memory mapped mode */ + s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; + s_mem_mapped_cfg.TimeOutPeriod = 0; + + if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @} + */ + +/** @addtogroup STM32F7308_DISCOVERY_QSPI_Private_Functions + * @{ + */ + +/** + * @brief QSPI MSP Initialization + * This function configures the hardware resources used in this example: + * - Peripheral's clock enable + * - Peripheral's GPIO Configuration + * - NVIC configuration for QSPI interrupt + * @retval None + */ +__weak void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /*##-1- Enable peripherals and GPIO Clocks #################################*/ + /* Enable the QuadSPI memory interface clock */ + QSPI_CLK_ENABLE(); + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + /* Enable GPIO clocks */ + QSPI_CS_GPIO_CLK_ENABLE(); + QSPI_CLK_GPIO_CLK_ENABLE(); + QSPI_D0_GPIO_CLK_ENABLE(); + QSPI_D1_GPIO_CLK_ENABLE(); + QSPI_D2_GPIO_CLK_ENABLE(); + QSPI_D3_GPIO_CLK_ENABLE(); + + /*##-2- Configure peripheral GPIO ##########################################*/ + /* QSPI CS GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CS_PIN; + gpio_init_structure.Alternate = QSPI_CS_PIN_AF; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &gpio_init_structure); + /* QSPI CLK GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CLK_PIN; + gpio_init_structure.Alternate = QSPI_CLK_PIN_AF; + gpio_init_structure.Pull = GPIO_NOPULL; + HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &gpio_init_structure); + /* QSPI D0 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D0_PIN; + gpio_init_structure.Alternate = QSPI_D0_PIN_AF; + HAL_GPIO_Init(QSPI_D0_GPIO_PORT, &gpio_init_structure); + /* QSPI D1 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D1_PIN; + gpio_init_structure.Alternate = QSPI_D1_PIN_AF; + HAL_GPIO_Init(QSPI_D1_GPIO_PORT, &gpio_init_structure); + /* QSPI D2 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D2_PIN; + gpio_init_structure.Alternate = QSPI_D2_PIN_AF; + HAL_GPIO_Init(QSPI_D2_GPIO_PORT, &gpio_init_structure); + /* QSPI D3 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D3_PIN; + gpio_init_structure.Alternate = QSPI_D3_PIN_AF; + HAL_GPIO_Init(QSPI_D3_GPIO_PORT, &gpio_init_structure); + + /*##-3- Configure the NVIC for QSPI #########################################*/ + /* NVIC configuration for QSPI interrupt */ + HAL_NVIC_SetPriority(QUADSPI_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(QUADSPI_IRQn); +} + +/** + * @brief QSPI MSP De-Initialization + * This function frees the hardware resources used in this example: + * - Disable the Peripheral's clock + * - Revert GPIO and NVIC configuration to their default state + * @retval None + */ +__weak void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + /*##-1- Disable the NVIC for QSPI ###########################################*/ + HAL_NVIC_DisableIRQ(QUADSPI_IRQn); + + /*##-2- Disable peripherals and GPIO Clocks ################################*/ + /* De-Configure QSPI pins */ + HAL_GPIO_DeInit(QSPI_CS_GPIO_PORT, QSPI_CS_PIN); + HAL_GPIO_DeInit(QSPI_CLK_GPIO_PORT, QSPI_CLK_PIN); + HAL_GPIO_DeInit(QSPI_D0_GPIO_PORT, QSPI_D0_PIN); + HAL_GPIO_DeInit(QSPI_D1_GPIO_PORT, QSPI_D1_PIN); + HAL_GPIO_DeInit(QSPI_D2_GPIO_PORT, QSPI_D2_PIN); + HAL_GPIO_DeInit(QSPI_D3_GPIO_PORT, QSPI_D3_PIN); + + /*##-3- Reset peripherals ##################################################*/ + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + + /* Disable the QuadSPI memory interface clock */ + QSPI_CLK_DISABLE(); +} + +/** + * @brief This function reset the QSPI memory. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + uint8_t reg; + + /* Send command RESET command in QPI mode (QUAD I/Os) */ + /* Initialize the reset enable command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = RESET_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + /* Send the reset memory command */ + s_command.Instruction = RESET_MEMORY_CMD; + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Send command RESET command in SPI mode */ + /* Initialize the reset enable command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = RESET_ENABLE_CMD; + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + /* Send the reset memory command */ + s_command.Instruction = RESET_MEMORY_CMD; + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* After reset CMD, 1000ms requested if QSPI memory SWReset occured during full chip erase operation */ + HAL_Delay( 1000 ); + + /* Configure automatic polling mode to wait the WIP bit=0 */ + s_config.Match = 0; + s_config.Mask = MX25L512_SR_WIP; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_1_LINE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Initialize the reading of status register */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations, command in 1 bit */ + /* Enable write operations */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = WRITE_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for write enabling */ + s_config.Match = MX25L512_SR_WREN; + s_config.Mask = MX25L512_SR_WREN; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_1_LINE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Update the configuration register with new dummy cycles */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = WRITE_STATUS_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable the Quad IO on the QSPI memory (Non-volatile bit) */ + reg |= MX25L512_SR_QUADEN; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* 40ms Write Status/Configuration Register Cycle Time */ + HAL_Delay( 40 ); + + return QSPI_OK; +} + +/** + * @brief This function set the QSPI memory in 4-byte address mode + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = ENTER_4_BYTE_ADDR_MODE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(hqspi) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait the memory is ready */ + if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function configure the dummy cycles on memory side. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg[2]; + + /* Initialize the reading of status register */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Initialize the reading of configuration register */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, &(reg[1]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations */ + if (QSPI_WriteEnable(hqspi) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update the configuration register with new dummy cycles */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = WRITE_STATUS_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 2; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* MX25L512_DUMMY_CYCLES_READ_QUAD = 3 for 10 cycles in QPI mode */ + MODIFY_REG( reg[1], MX25L512_CR_NB_DUMMY, (MX25L512_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(MX25L512_CR_NB_DUMMY))); + + /* Configure the write volatile configuration register command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(hqspi, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* 40ms Write Status/Configuration Register Cycle Time */ + HAL_Delay( 40 ); + + return QSPI_OK; +} + +/** + * @brief This function put QSPI memory in QPI mode (quad I/O). + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_EnterMemory_QPI( QSPI_HandleTypeDef *hqspi ) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Initialize the QPI enable command */ + /* QSPI memory is supported to be in SPI mode, so CMD on 1 LINE */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = ENTER_QUAD_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait the QUADEN bit=1 and WIP bit=0 */ + s_config.Match = MX25L512_SR_QUADEN; + s_config.Mask = MX25L512_SR_QUADEN|MX25L512_SR_WIP; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_4_LINES; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function put QSPI memory in SPI mode. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_ExitMemory_QPI( QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the QPI enable command */ + /* QSPI memory is supported to be in QPI mode, so CMD on 4 LINES */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = EXIT_QUAD_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function configure the Output driver strength on memory side. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_OutDrvStrengthCfg( QSPI_HandleTypeDef *hqspi ) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg[2]; + + /* Initialize the reading of status register */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Initialize the reading of configuration register */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, &(reg[1]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update the configuration register with new output driver strength */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = WRITE_STATUS_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 2; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Set Output Strength of the QSPI memory 15 ohms */ + MODIFY_REG( reg[1], MX25L512_CR_ODS, (MX25L512_CR_ODS_15 << POSITION_VAL(MX25L512_CR_ODS))); + + /* Configure the write volatile configuration register command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(hqspi, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function send a Write Enable and wait it is effective. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Enable write operations */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = WRITE_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for write enabling */ + s_config.Match = MX25L512_SR_WREN; + s_config.Mask = MX25L512_SR_WREN; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_4_LINES; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function read the SR of the memory and wait the EOP. + * @param hqspi: QSPI handle + * @param Timeout + * @retval None + */ +static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Configure automatic polling mode to wait for memory ready */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + s_config.Match = 0; + s_config.Mask = MX25L512_SR_WIP; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, Timeout) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_qspi.h b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_qspi.h new file mode 100644 index 00000000..643e84fe --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_qspi.h @@ -0,0 +1,159 @@ +/** + ****************************************************************************** + * @file stm32f7308_discovery_qspi.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f7308_discovery_qspi.c driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY + * @{ + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7308_DISCOVERY_QSPI_H +#define __STM32F7308_DISCOVERY_QSPI_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" +#include "../Components/mx25l512/mx25l512.h" + +/** @addtogroup STM32F7308_DISCOVERY_QSPI + * @{ + */ + + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup STM32F7308_DISCOVERY_QSPI_Exported_Constants STM32F7308_DISCOVERY_QSPI Exported Constants + * @{ + */ +/* QSPI Error codes */ +#define QSPI_OK ((uint8_t)0x00) +#define QSPI_ERROR ((uint8_t)0x01) +#define QSPI_BUSY ((uint8_t)0x02) +#define QSPI_NOT_SUPPORTED ((uint8_t)0x04) +#define QSPI_SUSPENDED ((uint8_t)0x08) + + +/* Definition for QSPI clock resources */ +#define QSPI_CLK_ENABLE() __HAL_RCC_QSPI_CLK_ENABLE() +#define QSPI_CLK_DISABLE() __HAL_RCC_QSPI_CLK_DISABLE() +#define QSPI_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_CLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_D0_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define QSPI_D1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define QSPI_D2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() +#define QSPI_D3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() + +#define QSPI_FORCE_RESET() __HAL_RCC_QSPI_FORCE_RESET() +#define QSPI_RELEASE_RESET() __HAL_RCC_QSPI_RELEASE_RESET() + +/* Definition for QSPI Pins */ +/* QSPI_CS */ +#define QSPI_CS_PIN GPIO_PIN_6 +#define QSPI_CS_GPIO_PORT GPIOB +#define QSPI_CS_PIN_AF GPIO_AF10_QUADSPI +/* QSPI_CLK */ +#define QSPI_CLK_PIN GPIO_PIN_2 +#define QSPI_CLK_GPIO_PORT GPIOB +#define QSPI_CLK_PIN_AF GPIO_AF9_QUADSPI +/* QSPI_D0 */ +#define QSPI_D0_PIN GPIO_PIN_9 +#define QSPI_D0_GPIO_PORT GPIOC +#define QSPI_D0_PIN_AF GPIO_AF9_QUADSPI +/* QSPI_D1 */ +#define QSPI_D1_PIN GPIO_PIN_10 +#define QSPI_D1_GPIO_PORT GPIOC +#define QSPI_D1_PIN_AF GPIO_AF9_QUADSPI +/* QSPI_D2 */ +#define QSPI_D2_PIN GPIO_PIN_2 +#define QSPI_D2_GPIO_PORT GPIOE +#define QSPI_D2_PIN_AF GPIO_AF9_QUADSPI +/* QSPI_D3 */ +#define QSPI_D3_PIN GPIO_PIN_13 +#define QSPI_D3_GPIO_PORT GPIOD +#define QSPI_D3_PIN_AF GPIO_AF9_QUADSPI + +/** + * @} + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup STM32F7308_DISCOVERY_QSPI_Exported_Types STM32F7308_DISCOVERY_QSPI Exported Types + * @{ + */ +/* QSPI Info */ +typedef struct { + uint32_t FlashSize; /*!< Size of the flash */ + uint32_t EraseSectorSize; /*!< Size of sectors for the erase operation */ + uint32_t EraseSectorsNumber; /*!< Number of sectors for the erase operation */ + uint32_t ProgPageSize; /*!< Size of pages for the program operation */ + uint32_t ProgPagesNumber; /*!< Number of pages for the program operation */ +} QSPI_Info; + +/** + * @} + */ + + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup STM32F7308_DISCOVERY_QSPI_Exported_Functions + * @{ + */ +uint8_t BSP_QSPI_Init (void); +uint8_t BSP_QSPI_DeInit (void); +uint8_t BSP_QSPI_Read (uint8_t* pData, uint32_t ReadAddr, uint32_t Size); +uint8_t BSP_QSPI_Write (uint8_t* pData, uint32_t WriteAddr, uint32_t Size); +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress); +uint8_t BSP_QSPI_Erase_Chip (void); +uint8_t BSP_QSPI_GetStatus (void); +uint8_t BSP_QSPI_GetInfo (QSPI_Info* pInfo); +uint8_t BSP_QSPI_EnableMemoryMappedMode(void); + +/* These functions can be modified in case the current settings + need to be changed for specific application needs */ +void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params); +void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7308_DISCOVERY_QSPI_H */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_ts.c b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_ts.c new file mode 100644 index 00000000..21aa30ce --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_ts.c @@ -0,0 +1,469 @@ +/** + ****************************************************************************** + * @file stm32f7308_discovery_ts.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the Touch + * Screen on STM32F7308-DISCOVERY evaluation board. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* File Info : ----------------------------------------------------------------- + User NOTES +1. How To use this driver: +-------------------------- + - This driver is used to drive the touch screen module of the STM32F7308-DISCOVERY + evaluation board on the FRIDA LCD mounted on MB1260 discovery board. + The touch screen driver IC is a FT6x36 type which share the same register naming + with FT6206 type. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the TS module using the BSP_TS_Init() function. This + function includes the MSP layer hardware resources initialization and the + communication layer configuration to start the TS use. The LCD size properties + (x and y) are passed as parameters. + Note: The FT6x36 requires a calibration. This should be done at application level. + Refer to BSP example to correctly calibrate the touch screen. + o If TS interrupt mode is desired, you must configure the TS interrupt mode + by calling the function BSP_TS_ITConfig(). The TS interrupt mode is generated + as an external interrupt whenever a touch is detected. + + + Touch screen use + o The touch screen state is captured whenever the function BSP_TS_GetState() is + used. This function returns information about the last LCD touch occurred + in the TS_StateTypeDef structure. +------------------------------------------------------------------------------*/ + +/* Dependencies +- stm32f7308_discovery_lcd.c +- ft6x06.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7308_discovery_ts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7308_DISCOVERY_TS STM32F7308_DISCOVERY_TS + * @{ + */ + +/** @defgroup STM32F7308-DISCOVERY_TS_Private_Types_Definitions TS Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308-DISCOVERY_TS_Private_Defines TS Private Types Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308-DISCOVERY_TS_Private_Macros TS Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308-DISCOVERY_TS_Imported_Variables TS Imported Variables + * @{ + */ + /** + * @} + */ + +/** @defgroup STM32F7308-DISCOVERY_TS_Private_Variables TS Private Variables + * @{ + */ +static TS_DrvTypeDef *tsDriver; +static uint8_t I2C_Address = 0; +static uint8_t tsOrientation = TS_SWAP_NONE; + +/* Table for touchscreen event information display on LCD : table indexed on enum @ref TS_TouchEventTypeDef information */ +char * ts_event_string_tab[TOUCH_EVENT_NB_MAX] = { "None", + "Press down", + "Lift up", + "Contact" + }; + +/* Table for touchscreen gesture Id information display on LCD : table indexed on enum @ref TS_GestureIdTypeDef information */ +char * ts_gesture_id_string_tab[GEST_ID_NB_MAX] = { "None", + "Move Up", + "Move Right", + "Move Down", + "Move Left", + "Zoom In", + "Zoom Out" + }; +/** + * @} + */ + +/** @defgroup STM32F7308-DISCOVERY_TS_Private_Function_Prototypes TS Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7308-DISCOVERY_TS_Public_Functions TS Public Functions + * @{ + */ +/** + * @brief Initializes and configures the touch screen functionalities and + * configures all necessary hardware resources (GPIOs, I2C, clocks..). + * @param ts_SizeX : Maximum X size of the TS area on LCD + * @param ts_SizeY : Maximum Y size of the TS area on LCD + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY) +{ + return (BSP_TS_InitEx(ts_SizeX, ts_SizeY, TS_ORIENTATION_LANDSCAPE)); +} + +/** + * @brief Initializes and configures the touch screen functionalities and + * configures all necessary hardware resources (GPIOs, I2C, clocks..) + * with a given orientation + * @param ts_SizeX : Maximum X size of the TS area on LCD + * @param ts_SizeY : Maximum Y size of the TS area on LCD + * @param orientation : TS_ORIENTATION_LANDSCAPE or TS_ORIENTATION_PORTRAIT + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_InitEx(uint16_t ts_SizeX, uint16_t ts_SizeY, uint8_t orientation) +{ + uint8_t ts_status = TS_OK; + + /* Note : I2C_Address is un-initialized here, but is not used at all in init function */ + /* but the prototype of Init() is like that in template and should be respected */ + + /* Initialize the communication channel to sensor (I2C) if necessary */ + /* that is initialization is done only once after a power up */ + ft6x06_ts_drv.Init(I2C_Address); + + /* Scan FT6x36 TouchScreen IC controller ID register by I2C Read */ + /* Verify this is a FT6x36, otherwise this is an error case */ + if(ft6x06_ts_drv.ReadID(TS_I2C_ADDRESS) == FT6x36_ID_VALUE) + { + /* Found FT6x36 : Initialize the TS driver structure */ + tsDriver = &ft6x06_ts_drv; + + I2C_Address = TS_I2C_ADDRESS; + + /* Get LCD chosen orientation */ + if(orientation == TS_ORIENTATION_PORTRAIT) + { + tsOrientation = TS_SWAP_X | TS_SWAP_Y; + } + else if(orientation == TS_ORIENTATION_LANDSCAPE_ROT180) + { + tsOrientation = TS_SWAP_XY; + } + else + { + tsOrientation = TS_SWAP_XY | TS_SWAP_Y; + } + + if(ts_status == TS_OK) + { + /* Software reset the TouchScreen */ + tsDriver->Reset(I2C_Address); + + /* Calibrate, Configure and Start the TouchScreen driver */ + tsDriver->Start(I2C_Address); + + } /* of if(ts_status == TS_OK) */ + } + else + { + ts_status = TS_DEVICE_NOT_FOUND; + } + + return (ts_status); +} + +/** + * @brief Configures and enables the touch screen interrupts. + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_ITConfig(void) +{ + uint8_t ts_status = TS_OK; + GPIO_InitTypeDef gpio_init_structure; + + /* Msp Init of GPIO used for TS_INT pin coming from TouchScreen driver IC FT6x36 */ + /* When touchscreen is operated in interrupt mode */ + BSP_TS_INT_MspInit(); + + /* Configure Interrupt mode for TS_INT pin falling edge : when a new touch is available */ + /* TS_INT pin is active on low level on new touch available */ + gpio_init_structure.Pin = TS_INT_PIN; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Mode = GPIO_MODE_IT_FALLING; + HAL_GPIO_Init(TS_INT_GPIO_PORT, &gpio_init_structure); + + /* Enable and set the TS_INT EXTI Interrupt to an intermediate priority */ + HAL_NVIC_SetPriority((IRQn_Type)(TS_INT_EXTI_IRQn), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(TS_INT_EXTI_IRQn)); + + /* Enable the TS in interrupt mode */ + /* In that case the INT output of FT6206 when new touch is available */ + /* is active on low level and directed on EXTI */ + tsDriver->EnableIT(I2C_Address); + + return (ts_status); +} + +/** + * @brief Returns status and positions of the touch screen. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State) +{ + static uint32_t _x[TS_MAX_NB_TOUCH] = {0, 0}; + static uint32_t _y[TS_MAX_NB_TOUCH] = {0, 0}; + uint8_t ts_status = TS_OK; + uint16_t tmp; + uint16_t Raw_x[TS_MAX_NB_TOUCH]; + uint16_t Raw_y[TS_MAX_NB_TOUCH]; + uint16_t xDiff; + uint16_t yDiff; + uint32_t index; +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + uint32_t weight = 0; + uint32_t area = 0; + uint32_t event = 0; +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + /* Check and update the number of touches active detected */ + TS_State->touchDetected = tsDriver->DetectTouch(I2C_Address); + if(TS_State->touchDetected) + { + for(index=0; index < TS_State->touchDetected; index++) + { + /* Get each touch coordinates */ + tsDriver->GetXY(I2C_Address, &(Raw_x[index]), &(Raw_y[index])); + + if(tsOrientation & TS_SWAP_XY) + { + tmp = Raw_x[index]; + Raw_x[index] = Raw_y[index]; + Raw_y[index] = tmp; + } + + if(tsOrientation & TS_SWAP_X) + { + Raw_x[index] = FT_6206_MAX_WIDTH_HEIGHT - 1 - Raw_x[index]; + } + + if(tsOrientation & TS_SWAP_Y) + { + Raw_y[index] = FT_6206_MAX_WIDTH_HEIGHT - 1 - Raw_y[index]; + } + + xDiff = Raw_x[index] > _x[index]? (Raw_x[index] - _x[index]): (_x[index] - Raw_x[index]); + yDiff = Raw_y[index] > _y[index]? (Raw_y[index] - _y[index]): (_y[index] - Raw_y[index]); + + if ((xDiff + yDiff) > 5) + { + _x[index] = Raw_x[index]; + _y[index] = Raw_y[index]; + } + + + TS_State->touchX[index] = _x[index]; + TS_State->touchY[index] = _y[index]; + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + + /* Get touch info related to the current touch */ + ft6x06_TS_GetTouchInfo(I2C_Address, index, &weight, &area, &event); + + /* Update TS_State structure */ + TS_State->touchWeight[index] = weight; + TS_State->touchArea[index] = area; + + /* Remap touch event */ + switch(event) + { + case FT6206_TOUCH_EVT_FLAG_PRESS_DOWN : + TS_State->touchEventId[index] = TOUCH_EVENT_PRESS_DOWN; + break; + case FT6206_TOUCH_EVT_FLAG_LIFT_UP : + TS_State->touchEventId[index] = TOUCH_EVENT_LIFT_UP; + break; + case FT6206_TOUCH_EVT_FLAG_CONTACT : + TS_State->touchEventId[index] = TOUCH_EVENT_CONTACT; + break; + case FT6206_TOUCH_EVT_FLAG_NO_EVENT : + TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT; + break; + default : + ts_status = TS_ERROR; + break; + } /* of switch(event) */ + +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + } /* of for(index=0; index < TS_State->touchDetected; index++) */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + /* Get gesture Id */ + ts_status = BSP_TS_Get_GestureId(TS_State); +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + } /* end of if(TS_State->touchDetected != 0) */ + + return (ts_status); +} + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +/** + * @brief Update gesture Id following a touch detected. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State) +{ + uint32_t gestureId = 0; + uint8_t ts_status = TS_OK; + + /* Get gesture Id */ + ft6x06_TS_GetGestureID(I2C_Address, &gestureId); + + /* Remap gesture Id to a TS_GestureIdTypeDef value */ + switch(gestureId) + { + case FT6206_GEST_ID_NO_GESTURE : + TS_State->gestureId = GEST_ID_NO_GESTURE; + break; + case FT6206_GEST_ID_MOVE_UP : + TS_State->gestureId = GEST_ID_MOVE_UP; + break; + case FT6206_GEST_ID_MOVE_RIGHT : + TS_State->gestureId = GEST_ID_MOVE_RIGHT; + break; + case FT6206_GEST_ID_MOVE_DOWN : + TS_State->gestureId = GEST_ID_MOVE_DOWN; + break; + case FT6206_GEST_ID_MOVE_LEFT : + TS_State->gestureId = GEST_ID_MOVE_LEFT; + break; + case FT6206_GEST_ID_ZOOM_IN : + TS_State->gestureId = GEST_ID_ZOOM_IN; + break; + case FT6206_GEST_ID_ZOOM_OUT : + TS_State->gestureId = GEST_ID_ZOOM_OUT; + break; + default : + ts_status = TS_ERROR; + break; + } /* of switch(gestureId) */ + + return(ts_status); +} +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + +/** @defgroup STM32F7308-DISCOVERY_TS_Private_Functions TS Private Functions + * @{ + */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +/** + * @brief Function used to reset all touch data before a new acquisition + * of touch information. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if OK, TE_ERROR if problem found. + */ +uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State) +{ + uint8_t ts_status = TS_ERROR; + uint32_t index; + + if (TS_State != (TS_StateTypeDef *)NULL) + { + TS_State->gestureId = GEST_ID_NO_GESTURE; + TS_State->touchDetected = 0; + + for(index = 0; index < TS_MAX_NB_TOUCH; index++) + { + TS_State->touchX[index] = 0; + TS_State->touchY[index] = 0; + TS_State->touchArea[index] = 0; + TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT; + TS_State->touchWeight[index] = 0; + } + + ts_status = TS_OK; + + } /* of if (TS_State != (TS_StateTypeDef *)NULL) */ + + return (ts_status); +} +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +/** + * @brief Initializes the TS_INT pin MSP. + * @retval None + */ +__weak void BSP_TS_INT_MspInit(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + TS_INT_GPIO_CLK_ENABLE(); + + /* GPIO configuration in input for TouchScreen interrupt signal on TS_INT pin */ + gpio_init_structure.Pin = TS_INT_PIN; + + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(TS_INT_GPIO_PORT, &gpio_init_structure); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_ts.h b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_ts.h new file mode 100644 index 00000000..c6018e9a --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7308-Discovery/stm32f7308_discovery_ts.h @@ -0,0 +1,199 @@ +/** + ****************************************************************************** + * @file stm32f7308_discovery_ts.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f7308_discovery_ts.c driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7308_DISCOVERY_TS_H +#define __STM32F7308_DISCOVERY_TS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7308_discovery.h" + +/* Include TouchScreen component driver */ +#include "../Components/ft6x06/ft6x06.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F7308_DISCOVERY_TS STM32F7308-DISCOVERY TS + * @{ + */ + + /** @defgroup STM32F7308-DISCOVERY_TS_Exported_Constants TS Exported Constants + * @{ + */ +/** @brief With FT6206 : maximum 2 touches detected simultaneously + */ +#define TS_MAX_NB_TOUCH ((uint32_t) FT6206_MAX_DETECTABLE_TOUCH) + +#define TS_NO_IRQ_PENDING ((uint8_t) 0) +#define TS_IRQ_PENDING ((uint8_t) 1) + +#define TS_SWAP_NONE ((uint8_t) 0x01) +#define TS_SWAP_X ((uint8_t) 0x02) +#define TS_SWAP_Y ((uint8_t) 0x04) +#define TS_SWAP_XY ((uint8_t) 0x08) + +#define TS_ORIENTATION_PORTRAIT ((uint8_t) 0x00) +#define TS_ORIENTATION_LANDSCAPE ((uint8_t) 0x01) +#define TS_ORIENTATION_LANDSCAPE_ROT180 ((uint8_t) 0x02) + + /** + * @} + */ + +/** @defgroup STM32F7308-DISCOVERY_TS_Exported_Types TS Exported Types + * @{ + */ +/** +* @brief TS_StateTypeDef +* Define TS State structure +*/ +typedef struct +{ + uint8_t touchDetected; /*!< Total number of active touches detected at last scan */ + uint16_t touchX[TS_MAX_NB_TOUCH]; /*!< Touch X[0], X[1] coordinates on 12 bits */ + uint16_t touchY[TS_MAX_NB_TOUCH]; /*!< Touch Y[0], Y[1] coordinates on 12 bits */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + uint8_t touchWeight[TS_MAX_NB_TOUCH]; /*!< Touch_Weight[0], Touch_Weight[1] : weight property of touches */ + uint8_t touchEventId[TS_MAX_NB_TOUCH]; /*!< Touch_EventId[0], Touch_EventId[1] : take value of type @ref TS_TouchEventTypeDef */ + uint8_t touchArea[TS_MAX_NB_TOUCH]; /*!< Touch_Area[0], Touch_Area[1] : touch area of each touch */ + uint32_t gestureId; /*!< type of gesture detected : take value of type @ref TS_GestureIdTypeDef */ +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +} TS_StateTypeDef; + +/** + * @brief TS_StatusTypeDef + * Define BSP_TS_xxx() functions possible return value, + * when status is returned by those functions. + */ +typedef enum +{ + TS_OK = 0x00, /*!< Touch Ok */ + TS_ERROR = 0x01, /*!< Touch Error */ + TS_TIMEOUT = 0x02, /*!< Touch Timeout */ + TS_DEVICE_NOT_FOUND = 0x03 /*!< Touchscreen device not found */ +} TS_StatusTypeDef; + +/** + * @brief TS_GestureIdTypeDef + * Define Possible managed gesture identification values returned by touch screen + * driver. + */ +typedef enum +{ + GEST_ID_NO_GESTURE = 0x00, /*!< Gesture not defined / recognized */ + GEST_ID_MOVE_UP = 0x01, /*!< Gesture Move Up */ + GEST_ID_MOVE_RIGHT = 0x02, /*!< Gesture Move Right */ + GEST_ID_MOVE_DOWN = 0x03, /*!< Gesture Move Down */ + GEST_ID_MOVE_LEFT = 0x04, /*!< Gesture Move Left */ + GEST_ID_ZOOM_IN = 0x05, /*!< Gesture Zoom In */ + GEST_ID_ZOOM_OUT = 0x06, /*!< Gesture Zoom Out */ + GEST_ID_NB_MAX = 0x07 /*!< max number of gesture id */ +} TS_GestureIdTypeDef; + +/** + * @brief TS_TouchEventTypeDef + * Define Possible touch events kind as returned values + * by touch screen IC Driver. + */ +typedef enum +{ + TOUCH_EVENT_NO_EVT = 0x00, /*!< Touch Event : undetermined */ + TOUCH_EVENT_PRESS_DOWN = 0x01, /*!< Touch Event Press Down */ + TOUCH_EVENT_LIFT_UP = 0x02, /*!< Touch Event Lift Up */ + TOUCH_EVENT_CONTACT = 0x03, /*!< Touch Event Contact */ + TOUCH_EVENT_NB_MAX = 0x04 /*!< max number of touch events kind */ +} TS_TouchEventTypeDef; + +/** + * @} + */ + +/** @addtogroup STM32F7308-DISCOVERY_TS_Imported_Variables TS Imported Variables + * @{ + */ +/** + * @brief Table for touchscreen event information display on LCD : + * table indexed on enum @ref TS_TouchEventTypeDef information + */ +extern char * ts_event_string_tab[TOUCH_EVENT_NB_MAX]; + +/** + * @brief Table for touchscreen gesture Id information display on LCD : table indexed + * on enum @ref TS_GestureIdTypeDef information + */ +extern char * ts_gesture_id_string_tab[GEST_ID_NB_MAX]; +/** + * @} + */ + +/** @defgroup STM32F7308-DISCOVERY_TS_Exported_Functions TS Exported Functions + * @{ + */ +uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY); +uint8_t BSP_TS_InitEx(uint16_t ts_SizeX, uint16_t ts_SizeY, uint8_t orientation); +uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State); + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State); +uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State); +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +uint8_t BSP_TS_ITConfig(void); + +/* These __weak function can be surcharged by application code in case the current settings + need to be changed for specific (example GPIO allocation) */ +void BSP_TS_INT_MspInit(void); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7308_DISCOVERY_TS_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/Release_Notes.html new file mode 100644 index 00000000..22f6764a --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/Release_Notes.html @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Release Notes for STM32746G-Discovery BSP Driver + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for STM32F7508-Discovery BSP Driver

+

Copyright +2018 STMicroelectronics

+

+
+

 

+ + + + + + +

The BSP (Board Specific +Package) drivers are parts of the STM32Cube package based on the HAL +drivers and provide a set of high level APIs relative to the hardware +components and features in the evaluation boards, discovery kits and nucleo +boards coming with the STM32Cube package for a given STM32 serie.

+

The BSP drivers allow a quick access to the boards’ +services using high level APIs and without any specific configuration as the +link with the HAL and the external components is done in intrinsic within the drivers.
+

+

From project settings points of view, user has only +to add the necessary driver’s files in the workspace and call the needed +functions from examples. However some low level +configuration functions are weak and can be overridden by the applications if user +wants to change some BSP drivers default behavior.

+ + +

    Update History

+ +

V1.0.0 / 19-October-2018

+ + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • First official release +of the STM32F7508-DISCO board BSP +drivers
  • +

Dependencies

+ + + + + + +
  • STM32F7xx_HAL_Driver V1.2.6
    +
  • BSP Common V4.0.1

License

+

This software component is licensed by ST under BSD 3-Clause +license, the "License"; You may not use this component except +in compliance with the License. You may obtain a copy of the License at:

+ +

https://opensource.org/licenses/BSD-3-Clause

+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery.c b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery.c new file mode 100644 index 00000000..bcb6e2fd --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery.c @@ -0,0 +1,886 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery.c + * @author MCD Application Team + * @brief This file provides a set of firmware functions to manage LEDs, + * push-buttons and COM ports available on STM32F7508-Discovery + * board(MB1191) from STMicroelectronics. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_uart.c +- stm32f7xx_hal_i2c.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7508_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_LOW_LEVEL STM32F7508_DISCOVERY_LOW_LEVEL + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_LOW_LEVEL_Private_TypesDefinitions STM32F7508_DISCOVERY_LOW_LEVEL Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_LOW_LEVEL_Private_Defines STM32F7508_DISCOVERY_LOW_LEVEL Private Defines + * @{ + */ +/** + * @brief STM32F7508 DISCOVERY BSP Driver version number V2.0.2 + */ +#define __STM32F7508_DISCO_BSP_VERSION_MAIN (0x02) /*!< [31:24] main version */ +#define __STM32F7508_DISCO_BSP_VERSION_SUB1 (0x00) /*!< [23:16] sub1 version */ +#define __STM32F7508_DISCO_BSP_VERSION_SUB2 (0x02) /*!< [15:8] sub2 version */ +#define __STM32F7508_DISCO_BSP_VERSION_RC (0x00) /*!< [7:0] release candidate */ +#define __STM32F7508_DISCO_BSP_VERSION ((__STM32F7508_DISCO_BSP_VERSION_MAIN << 24)\ + |(__STM32F7508_DISCO_BSP_VERSION_SUB1 << 16)\ + |(__STM32F7508_DISCO_BSP_VERSION_SUB2 << 8 )\ + |(__STM32F7508_DISCO_BSP_VERSION_RC)) +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_LOW_LEVEL_Private_Macros STM32F7508_DISCOVERY_LOW_LEVEL Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_LOW_LEVEL_Private_Variables STM32F7508_DISCOVERY_LOW_LEVEL Private Variables + * @{ + */ + +const uint32_t GPIO_PIN[LEDn] = {LED1_PIN}; + +GPIO_TypeDef* BUTTON_PORT[BUTTONn] = {WAKEUP_BUTTON_GPIO_PORT, + TAMPER_BUTTON_GPIO_PORT, + KEY_BUTTON_GPIO_PORT}; + +const uint16_t BUTTON_PIN[BUTTONn] = {WAKEUP_BUTTON_PIN, + TAMPER_BUTTON_PIN, + KEY_BUTTON_PIN}; + +const uint16_t BUTTON_IRQn[BUTTONn] = {WAKEUP_BUTTON_EXTI_IRQn, + TAMPER_BUTTON_EXTI_IRQn, + KEY_BUTTON_EXTI_IRQn}; + +USART_TypeDef* COM_USART[COMn] = {DISCOVERY_COM1}; + +GPIO_TypeDef* COM_TX_PORT[COMn] = {DISCOVERY_COM1_TX_GPIO_PORT}; + +GPIO_TypeDef* COM_RX_PORT[COMn] = {DISCOVERY_COM1_RX_GPIO_PORT}; + +const uint16_t COM_TX_PIN[COMn] = {DISCOVERY_COM1_TX_PIN}; + +const uint16_t COM_RX_PIN[COMn] = {DISCOVERY_COM1_RX_PIN}; + +const uint16_t COM_TX_AF[COMn] = {DISCOVERY_COM1_TX_AF}; + +const uint16_t COM_RX_AF[COMn] = {DISCOVERY_COM1_RX_AF}; + +static I2C_HandleTypeDef hI2cAudioHandler = {0}; +static I2C_HandleTypeDef hI2cExtHandler = {0}; + +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_LOW_LEVEL_Private_FunctionPrototypes STM32F7508_DISCOVERY_LOW_LEVEL Private Function Prototypes + * @{ + */ +static void I2Cx_MspInit(I2C_HandleTypeDef *i2c_handler); +static void I2Cx_Init(I2C_HandleTypeDef *i2c_handler); + +static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static HAL_StatusTypeDef I2Cx_IsDeviceReady(I2C_HandleTypeDef *i2c_handler, uint16_t DevAddress, uint32_t Trials); +static void I2Cx_Error(I2C_HandleTypeDef *i2c_handler, uint8_t Addr); + +/* AUDIO IO functions */ +void AUDIO_IO_Init(void); +void AUDIO_IO_DeInit(void); +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value); +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg); +void AUDIO_IO_Delay(uint32_t Delay); + +/* TOUCHSCREEN IO functions */ +void TS_IO_Init(void); +void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg); +void TS_IO_Delay(uint32_t Delay); + +/* CAMERA IO functions */ +void CAMERA_IO_Init(void); +void CAMERA_Delay(uint32_t Delay); +void CAMERA_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +uint8_t CAMERA_IO_Read(uint8_t Addr, uint8_t Reg); + +/* I2C EEPROM IO function */ +void EEPROM_IO_Init(void); +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials); +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_LOW_LEVEL_Exported_Functions STM32F7508_DISCOVERY_LOW_LEVELSTM32F7508_DISCOVERY_LOW_LEVEL Exported Functions + * @{ + */ + + /** + * @brief This method returns the STM32F7508 DISCOVERY BSP Driver revision + * @retval version: 0xXYZR (8bits for each decimal, R for RC) + */ +uint32_t BSP_GetVersion(void) +{ + return __STM32F7508_DISCO_BSP_VERSION; +} + +/** + * @brief Configures LED on GPIO. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED1 + * @retval None + */ +void BSP_LED_Init(Led_TypeDef Led) +{ + GPIO_InitTypeDef gpio_init_structure; + GPIO_TypeDef* gpio_led; + + if (Led == LED1) + { + gpio_led = LED1_GPIO_PORT; + /* Enable the GPIO_LED clock */ + LED1_GPIO_CLK_ENABLE(); + + /* Configure the GPIO_LED pin */ + gpio_init_structure.Pin = GPIO_PIN[Led]; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + + HAL_GPIO_Init(gpio_led, &gpio_init_structure); + + /* By default, turn off LED */ + HAL_GPIO_WritePin(gpio_led, GPIO_PIN[Led], GPIO_PIN_RESET); + } +} + +/** + * @brief DeInit LEDs. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED1 + * @note Led DeInit does not disable the GPIO clock + * @retval None + */ +void BSP_LED_DeInit(Led_TypeDef Led) +{ + GPIO_InitTypeDef gpio_init_structure; + GPIO_TypeDef* gpio_led; + + if (Led == LED1) + { + gpio_led = LED1_GPIO_PORT; + /* Turn off LED */ + HAL_GPIO_WritePin(gpio_led, GPIO_PIN[Led], GPIO_PIN_RESET); + /* Configure the GPIO_LED pin */ + gpio_init_structure.Pin = GPIO_PIN[Led]; + HAL_GPIO_DeInit(gpio_led, gpio_init_structure.Pin); + } +} + +/** + * @brief Turns selected LED On. + * @param Led: LED to be set on + * This parameter can be one of the following values: + * @arg LED1 + * @retval None + */ +void BSP_LED_On(Led_TypeDef Led) +{ + GPIO_TypeDef* gpio_led; + + if (Led == LED1) /* Switch On LED connected to GPIO */ + { + gpio_led = LED1_GPIO_PORT; + HAL_GPIO_WritePin(gpio_led, GPIO_PIN[Led], GPIO_PIN_SET); + } +} + +/** + * @brief Turns selected LED Off. + * @param Led: LED to be set off + * This parameter can be one of the following values: + * @arg LED1 + * @retval None + */ +void BSP_LED_Off(Led_TypeDef Led) +{ + GPIO_TypeDef* gpio_led; + + if (Led == LED1) /* Switch Off LED connected to GPIO */ + { + gpio_led = LED1_GPIO_PORT; + HAL_GPIO_WritePin(gpio_led, GPIO_PIN[Led], GPIO_PIN_RESET); + } +} + +/** + * @brief Toggles the selected LED. + * @param Led: LED to be toggled + * This parameter can be one of the following values: + * @arg LED1 + * @retval None + */ +void BSP_LED_Toggle(Led_TypeDef Led) +{ + GPIO_TypeDef* gpio_led; + + if (Led == LED1) /* Toggle LED connected to GPIO */ + { + gpio_led = LED1_GPIO_PORT; + HAL_GPIO_TogglePin(gpio_led, GPIO_PIN[Led]); + } +} + +/** + * @brief Configures button GPIO and EXTI Line. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_TAMPER: Tamper Push Button + * @arg BUTTON_KEY: Key Push Button + * @param ButtonMode: Button mode + * This parameter can be one of the following values: + * @arg BUTTON_MODE_GPIO: Button will be used as simple IO + * @arg BUTTON_MODE_EXTI: Button will be connected to EXTI line + * with interrupt generation capability + * @note On STM32F7508-Discovery board, the three buttons (Wakeup, Tamper and key buttons) + * are mapped on the same push button named "User" + * on the board serigraphy. + * @retval None + */ +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef ButtonMode) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable the BUTTON clock */ + BUTTONx_GPIO_CLK_ENABLE(Button); + + if(ButtonMode == BUTTON_MODE_GPIO) + { + /* Configure Button pin as input */ + gpio_init_structure.Pin = BUTTON_PIN[Button]; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure); + } + + if(ButtonMode == BUTTON_MODE_EXTI) + { + /* Configure Button pin as input with External interrupt */ + gpio_init_structure.Pin = BUTTON_PIN[Button]; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + + if(Button != BUTTON_WAKEUP) + { + gpio_init_structure.Mode = GPIO_MODE_IT_FALLING; + } + else + { + gpio_init_structure.Mode = GPIO_MODE_IT_RISING; + } + + HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure); + + /* Enable and set Button EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(BUTTON_IRQn[Button]), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + } +} + +/** + * @brief Push Button DeInit. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_TAMPER: Tamper Push Button + * @arg BUTTON_KEY: Key Push Button + * @note On STM32F7508-Discovery board, the three buttons (Wakeup, Tamper and key buttons) + * are mapped on the same push button named "User" + * on the board serigraphy. + * @note PB DeInit does not disable the GPIO clock + * @retval None + */ +void BSP_PB_DeInit(Button_TypeDef Button) +{ + GPIO_InitTypeDef gpio_init_structure; + + gpio_init_structure.Pin = BUTTON_PIN[Button]; + HAL_NVIC_DisableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + HAL_GPIO_DeInit(BUTTON_PORT[Button], gpio_init_structure.Pin); +} + + +/** + * @brief Returns the selected button state. + * @param Button: Button to be checked + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_TAMPER: Tamper Push Button + * @arg BUTTON_KEY: Key Push Button + * @note On STM32F7508-Discovery board, the three buttons (Wakeup, Tamper and key buttons) + * are mapped on the same push button named "User" + * on the board serigraphy. + * @retval The Button GPIO pin value + */ +uint32_t BSP_PB_GetState(Button_TypeDef Button) +{ + return HAL_GPIO_ReadPin(BUTTON_PORT[Button], BUTTON_PIN[Button]); +} + +/** + * @brief Configures COM port. + * @param COM: COM port to be configured. + * This parameter can be one of the following values: + * @arg COM1 + * @arg COM2 + * @param huart: Pointer to a UART_HandleTypeDef structure that contains the + * configuration information for the specified USART peripheral. + * @retval None + */ +void BSP_COM_Init(COM_TypeDef COM, UART_HandleTypeDef *huart) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable GPIO clock */ + DISCOVERY_COMx_TX_GPIO_CLK_ENABLE(COM); + DISCOVERY_COMx_RX_GPIO_CLK_ENABLE(COM); + + /* Enable USART clock */ + DISCOVERY_COMx_CLK_ENABLE(COM); + + /* Configure USART Tx as alternate function */ + gpio_init_structure.Pin = COM_TX_PIN[COM]; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Alternate = COM_TX_AF[COM]; + HAL_GPIO_Init(COM_TX_PORT[COM], &gpio_init_structure); + + /* Configure USART Rx as alternate function */ + gpio_init_structure.Pin = COM_RX_PIN[COM]; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = COM_RX_AF[COM]; + HAL_GPIO_Init(COM_RX_PORT[COM], &gpio_init_structure); + + /* USART configuration */ + huart->Instance = COM_USART[COM]; + HAL_UART_Init(huart); +} + +/** + * @brief DeInit COM port. + * @param COM: COM port to be configured. + * This parameter can be one of the following values: + * @arg COM1 + * @arg COM2 + * @param huart: Pointer to a UART_HandleTypeDef structure that contains the + * configuration information for the specified USART peripheral. + * @retval None + */ +void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart) +{ + /* USART configuration */ + huart->Instance = COM_USART[COM]; + HAL_UART_DeInit(huart); + + /* Enable USART clock */ + DISCOVERY_COMx_CLK_DISABLE(COM); + + /* DeInit GPIO pins can be done in the application + (by surcharging this __weak function) */ + + /* GPIO pins clock, DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/******************************************************************************* + BUS OPERATIONS +*******************************************************************************/ + +/******************************* I2C Routines *********************************/ +/** + * @brief Initializes I2C MSP. + * @param i2c_handler : I2C handler + * @retval None + */ +static void I2Cx_MspInit(I2C_HandleTypeDef *i2c_handler) +{ + GPIO_InitTypeDef gpio_init_structure; + + if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cAudioHandler)) + { + /* AUDIO and LCD I2C MSP init */ + + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + DISCOVERY_AUDIO_I2Cx_SCL_SDA_GPIO_CLK_ENABLE(); + + /* Configure I2C Tx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_AUDIO_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = DISCOVERY_AUDIO_I2Cx_SCL_SDA_AF; + HAL_GPIO_Init(DISCOVERY_AUDIO_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C Rx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_AUDIO_I2Cx_SDA_PIN; + HAL_GPIO_Init(DISCOVERY_AUDIO_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + DISCOVERY_AUDIO_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + DISCOVERY_AUDIO_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + DISCOVERY_AUDIO_I2Cx_RELEASE_RESET(); + + /* Enable and set I2Cx Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_AUDIO_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_AUDIO_I2Cx_EV_IRQn); + + /* Enable and set I2Cx Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_AUDIO_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_AUDIO_I2Cx_ER_IRQn); + } + else + { + /* External, camera and Arduino connector I2C MSP init */ + + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_CLK_ENABLE(); + + /* Configure I2C Tx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_EXT_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = DISCOVERY_EXT_I2Cx_SCL_SDA_AF; + HAL_GPIO_Init(DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C Rx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_EXT_I2Cx_SDA_PIN; + HAL_GPIO_Init(DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + DISCOVERY_EXT_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + DISCOVERY_EXT_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + DISCOVERY_EXT_I2Cx_RELEASE_RESET(); + + /* Enable and set I2Cx Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_EXT_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_EXT_I2Cx_EV_IRQn); + + /* Enable and set I2Cx Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_EXT_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_EXT_I2Cx_ER_IRQn); + } +} + +/** + * @brief Initializes I2C HAL. + * @param i2c_handler : I2C handler + * @retval None + */ +static void I2Cx_Init(I2C_HandleTypeDef *i2c_handler) +{ + if(HAL_I2C_GetState(i2c_handler) == HAL_I2C_STATE_RESET) + { + if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cAudioHandler)) + { + /* Audio and LCD I2C configuration */ + i2c_handler->Instance = DISCOVERY_AUDIO_I2Cx; + } + else + { + /* External, camera and Arduino connector I2C configuration */ + i2c_handler->Instance = DISCOVERY_EXT_I2Cx; + } + i2c_handler->Init.Timing = DISCOVERY_I2Cx_TIMING; + i2c_handler->Init.OwnAddress1 = 0; + i2c_handler->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + i2c_handler->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + i2c_handler->Init.OwnAddress2 = 0; + i2c_handler->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + i2c_handler->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + + /* Init the I2C */ + I2Cx_MspInit(i2c_handler); + HAL_I2C_Init(i2c_handler); + } +} + +/** + * @brief Reads multiple data. + * @param i2c_handler : I2C handler + * @param Addr: I2C address + * @param Reg: Reg address + * @param MemAddress: Memory address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval Number of read data + */ +static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef *i2c_handler, + uint8_t Addr, + uint16_t Reg, + uint16_t MemAddress, + uint8_t *Buffer, + uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Read(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* I2C error occurred */ + I2Cx_Error(i2c_handler, Addr); + } + return status; +} + +/** + * @brief Writes a value in a register of the device through BUS in using DMA mode. + * @param i2c_handler : I2C handler + * @param Addr: Device address on BUS Bus. + * @param Reg: The target register address to write + * @param MemAddress: Memory address + * @param Buffer: The target register value to be written + * @param Length: buffer size to be written + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef *i2c_handler, + uint8_t Addr, + uint16_t Reg, + uint16_t MemAddress, + uint8_t *Buffer, + uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Write(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* Re-Initiaize the I2C Bus */ + I2Cx_Error(i2c_handler, Addr); + } + return status; +} + +/** + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param i2c_handler : I2C handler + * @param DevAddress: Target device address + * @param Trials: Number of trials + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_IsDeviceReady(I2C_HandleTypeDef *i2c_handler, uint16_t DevAddress, uint32_t Trials) +{ + return (HAL_I2C_IsDeviceReady(i2c_handler, DevAddress, Trials, 1000)); +} + +/** + * @brief Manages error callback by re-initializing I2C. + * @param i2c_handler : I2C handler + * @param Addr: I2C Address + * @retval None + */ +static void I2Cx_Error(I2C_HandleTypeDef *i2c_handler, uint8_t Addr) +{ + /* De-initialize the I2C communication bus */ + HAL_I2C_DeInit(i2c_handler); + + /* Re-Initialize the I2C communication bus */ + I2Cx_Init(i2c_handler); +} + +/******************************************************************************* + LINK OPERATIONS +*******************************************************************************/ + +/********************************* LINK AUDIO *********************************/ + +/** + * @brief Initializes Audio low level. + * @retval None + */ +void AUDIO_IO_Init(void) +{ + I2Cx_Init(&hI2cAudioHandler); +} + +/** + * @brief Deinitializes Audio low level. + * @retval None + */ +void AUDIO_IO_DeInit(void) +{ +} + +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param Value: Data to be written + * @retval None + */ +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value) +{ + uint16_t tmp = Value; + + Value = ((uint16_t)(tmp >> 8) & 0x00FF); + + Value |= ((uint16_t)(tmp << 8)& 0xFF00); + + I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_16BIT,(uint8_t*)&Value, 2); +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @retval Data to be read + */ +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg) +{ + uint16_t read_value = 0, tmp = 0; + + I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&read_value, 2); + + tmp = ((uint16_t)(read_value >> 8) & 0x00FF); + + tmp |= ((uint16_t)(read_value << 8)& 0xFF00); + + read_value = tmp; + + return read_value; +} + +/** + * @brief AUDIO Codec delay + * @param Delay: Delay in ms + * @retval None + */ +void AUDIO_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/********************************* LINK CAMERA ********************************/ + +/** + * @brief Initializes Camera low level. + * @retval None + */ +void CAMERA_IO_Init(void) +{ + I2Cx_Init(&hI2cExtHandler); +} + +/** + * @brief Camera writes single data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Value: Data to be written + * @retval None + */ +void CAMERA_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_WriteMultiple(&hI2cExtHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT,(uint8_t*)&Value, 1); +} + +/** + * @brief Camera reads single data. + * @param Addr: I2C address + * @param Reg: Register address + * @retval Read data + */ +uint8_t CAMERA_IO_Read(uint8_t Addr, uint8_t Reg) +{ + uint8_t read_value = 0; + + I2Cx_ReadMultiple(&hI2cExtHandler, Addr, Reg, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&read_value, 1); + + return read_value; +} + +/** + * @brief Camera delay + * @param Delay: Delay in ms + * @retval None + */ +void CAMERA_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/******************************** LINK I2C EEPROM *****************************/ + +/** + * @brief Initializes peripherals used by the I2C EEPROM driver. + * @retval None + */ +void EEPROM_IO_Init(void) +{ + I2Cx_Init(&hI2cExtHandler); +} + +/** + * @brief Write data to I2C EEPROM driver in using DMA channel. + * @param DevAddress: Target device address + * @param MemAddress: Internal memory address + * @param pBuffer: Pointer to data buffer + * @param BufferSize: Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize) +{ + return (I2Cx_WriteMultiple(&hI2cExtHandler, DevAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, pBuffer, BufferSize)); +} + +/** + * @brief Read data from I2C EEPROM driver in using DMA channel. + * @param DevAddress: Target device address + * @param MemAddress: Internal memory address + * @param pBuffer: Pointer to data buffer + * @param BufferSize: Amount of data to be read + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize) +{ + return (I2Cx_ReadMultiple(&hI2cExtHandler, DevAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, pBuffer, BufferSize)); +} + +/** + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param DevAddress: Target device address + * @param Trials: Number of trials + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials) +{ + return (I2Cx_IsDeviceReady(&hI2cExtHandler, DevAddress, Trials)); +} + +/********************************* LINK TOUCHSCREEN *********************************/ + +/** + * @brief Initializes Touchscreen low level. + * @retval None + */ +void TS_IO_Init(void) +{ + I2Cx_Init(&hI2cAudioHandler); +} + +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param Value: Data to be written + * @retval None + */ +void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT,(uint8_t*)&Value, 1); +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @retval Data to be read + */ +uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg) +{ + uint8_t read_value = 0; + + I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&read_value, 1); + + return read_value; +} + +/** + * @brief TS delay + * @param Delay: Delay in ms + * @retval None + */ +void TS_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery.h b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery.h new file mode 100644 index 00000000..6e4fc509 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery.h @@ -0,0 +1,323 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery.h + * @author MCD Application Team + * @brief This file contains definitions for STM32F7508_DISCOVERY's LEDs, + * push-buttons and COM ports hardware resources. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7508_DISCOVERY_H +#define __STM32F7508_DISCOVERY_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY_LOW_LEVEL + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_LOW_LEVEL_Exported_Types STM32F7508_DISCOVERY_LOW_LEVEL Exported Types + * @{ + */ +typedef enum +{ +LED1 = 0, +LED_GREEN = LED1, +}Led_TypeDef; + +typedef enum +{ + BUTTON_WAKEUP = 0, + BUTTON_TAMPER = 1, + BUTTON_KEY = 2 +}Button_TypeDef; + +typedef enum +{ + BUTTON_MODE_GPIO = 0, + BUTTON_MODE_EXTI = 1 +}ButtonMode_TypeDef; + +typedef enum +{ + COM1 = 0, + COM2 = 1 +}COM_TypeDef; +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_LOW_LEVEL_Exported_Constants STM32F7508_DISCOVERY_LOW_LEVEL Exported Constants + * @{ + */ + +/** + * @brief Define for STM32F7508_DISCOVERY board + */ +#if !defined (USE_STM32F7508_DISCO) + #define USE_STM32F7508_DISCO +#endif + +/** @addtogroup STM32F7508_DISCOVERY_LOW_LEVEL_LED + * @{ + */ + +#define LEDn ((uint8_t)1) + +#define LED1_GPIO_PORT GPIOI +#define LED1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define LED1_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define LED1_PIN GPIO_PIN_1 + +/** + * @} + */ + +/** @addtogroup STM32F7508_DISCOVERY_LOW_LEVEL_BUTTON + * @{ + */ +#define BUTTONn ((uint8_t)3) + +/** + * @brief Wakeup push-button + */ +#define WAKEUP_BUTTON_PIN GPIO_PIN_11 +#define WAKEUP_BUTTON_GPIO_PORT GPIOI +#define WAKEUP_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define WAKEUP_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define WAKEUP_BUTTON_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief Tamper push-button + */ +#define TAMPER_BUTTON_PIN GPIO_PIN_11 +#define TAMPER_BUTTON_GPIO_PORT GPIOI +#define TAMPER_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define TAMPER_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define TAMPER_BUTTON_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief Key push-button + */ +#define KEY_BUTTON_PIN GPIO_PIN_11 +#define KEY_BUTTON_GPIO_PORT GPIOI +#define KEY_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define KEY_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define KEY_BUTTON_EXTI_IRQn EXTI15_10_IRQn + +#define BUTTONx_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == 0) WAKEUP_BUTTON_GPIO_CLK_ENABLE(); else\ + if((__INDEX__) == 1) TAMPER_BUTTON_GPIO_CLK_ENABLE(); else\ + KEY_BUTTON_GPIO_CLK_ENABLE(); } while(0) + +#define BUTTONx_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? WAKEUP_BUTTON_GPIO_CLK_DISABLE() :\ + ((__INDEX__) == 1) ? TAMPER_BUTTON_GPIO_CLK_DISABLE() : KEY_BUTTON_GPIO_CLK_DISABLE()) + +/** + * @} + */ + +/** @addtogroup STM32F7508_DISCOVERY_LOW_LEVEL_SIGNAL + * @{ + */ +#define SIGNALn ((uint8_t)1) + +/** + * @brief SD-detect signal + */ +#define SD_DETECT_PIN GPIO_PIN_13 +#define SD_DETECT_GPIO_PORT GPIOC +#define SD_DETECT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define SD_DETECT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE() +#define SD_DETECT_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief Touch screen interrupt signal + */ +#define TS_INT_PIN GPIO_PIN_13 +#define TS_INT_GPIO_PORT GPIOI +#define TS_INT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define TS_INT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define TS_INT_EXTI_IRQn EXTI15_10_IRQn + +/** + * @} + */ + +/** @addtogroup STM32F7508_DISCOVERY_LOW_LEVEL_COM + * @{ + */ +#define COMn ((uint8_t)1) + +/** + * @brief Definition for COM port1, connected to USART1 + */ +#define DISCOVERY_COM1 USART1 +#define DISCOVERY_COM1_CLK_ENABLE() __HAL_RCC_USART1_CLK_ENABLE() +#define DISCOVERY_COM1_CLK_DISABLE() __HAL_RCC_USART1_CLK_DISABLE() + +#define DISCOVERY_COM1_TX_PIN GPIO_PIN_9 +#define DISCOVERY_COM1_TX_GPIO_PORT GPIOA +#define DISCOVERY_COM1_TX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define DISCOVERY_COM1_TX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define DISCOVERY_COM1_TX_AF GPIO_AF7_USART1 + +#define DISCOVERY_COM1_RX_PIN GPIO_PIN_7 +#define DISCOVERY_COM1_RX_GPIO_PORT GPIOB +#define DISCOVERY_COM1_RX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define DISCOVERY_COM1_RX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE() +#define DISCOVERY_COM1_RX_AF GPIO_AF7_USART1 + +#define DISCOVERY_COM1_IRQn USART1_IRQn + +#define DISCOVERY_COMx_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) DISCOVERY_COM1_CLK_ENABLE(); } while(0) +#define DISCOVERY_COMx_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? DISCOVERY_COM1_CLK_DISABLE() : 0) + +#define DISCOVERY_COMx_TX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) DISCOVERY_COM1_TX_GPIO_CLK_ENABLE(); } while(0) +#define DISCOVERY_COMx_TX_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? DISCOVERY_COM1_TX_GPIO_CLK_DISABLE() : 0) + +#define DISCOVERY_COMx_RX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) DISCOVERY_COM1_RX_GPIO_CLK_ENABLE(); } while(0) +#define DISCOVERY_COMx_RX_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? DISCOVERY_COM1_RX_GPIO_CLK_DISABLE() : 0) + +/* Exported constant IO ------------------------------------------------------*/ + +#define LCD_I2C_ADDRESS ((uint16_t)0x70) +#define CAMERA_I2C_ADDRESS ((uint16_t)0x60) +#define AUDIO_I2C_ADDRESS ((uint16_t)0x34) +#define EEPROM_I2C_ADDRESS_A01 ((uint16_t)0xA0) +#define EEPROM_I2C_ADDRESS_A02 ((uint16_t)0xA6) +#define TS_I2C_ADDRESS ((uint16_t)0x70) + +/* I2C clock speed configuration (in Hz) + WARNING: + Make sure that this define is not already declared in other files (ie. + stm32f7508_discovery.h file). It can be used in parallel by other modules. */ +#ifndef I2C_SPEED + #define I2C_SPEED ((uint32_t)100000) +#endif /* I2C_SPEED */ + +/* User can use this section to tailor I2Cx/I2Cx instance used and associated + resources */ +/* Definition for AUDIO and LCD I2Cx resources */ +#define DISCOVERY_AUDIO_I2Cx I2C3 +#define DISCOVERY_AUDIO_I2Cx_CLK_ENABLE() __HAL_RCC_I2C3_CLK_ENABLE() +#define DISCOVERY_AUDIO_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE() +#define DISCOVERY_AUDIO_I2Cx_SCL_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() + +#define DISCOVERY_AUDIO_I2Cx_FORCE_RESET() __HAL_RCC_I2C3_FORCE_RESET() +#define DISCOVERY_AUDIO_I2Cx_RELEASE_RESET() __HAL_RCC_I2C3_RELEASE_RESET() + +/* Definition for I2Cx Pins */ +#define DISCOVERY_AUDIO_I2Cx_SCL_PIN GPIO_PIN_7 +#define DISCOVERY_AUDIO_I2Cx_SCL_SDA_GPIO_PORT GPIOH +#define DISCOVERY_AUDIO_I2Cx_SCL_SDA_AF GPIO_AF4_I2C3 +#define DISCOVERY_AUDIO_I2Cx_SDA_PIN GPIO_PIN_8 + +/* I2C interrupt requests */ +#define DISCOVERY_AUDIO_I2Cx_EV_IRQn I2C3_EV_IRQn +#define DISCOVERY_AUDIO_I2Cx_ER_IRQn I2C3_ER_IRQn + +/* Definition for external, camera and Arduino connector I2Cx resources */ +#define DISCOVERY_EXT_I2Cx I2C1 +#define DISCOVERY_EXT_I2Cx_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE() +#define DISCOVERY_EXT_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE() +#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() + +#define DISCOVERY_EXT_I2Cx_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET() +#define DISCOVERY_EXT_I2Cx_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET() + +/* Definition for I2Cx Pins */ +#define DISCOVERY_EXT_I2Cx_SCL_PIN GPIO_PIN_8 +#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT GPIOB +#define DISCOVERY_EXT_I2Cx_SCL_SDA_AF GPIO_AF4_I2C1 +#define DISCOVERY_EXT_I2Cx_SDA_PIN GPIO_PIN_9 + +/* I2C interrupt requests */ +#define DISCOVERY_EXT_I2Cx_EV_IRQn I2C1_EV_IRQn +#define DISCOVERY_EXT_I2Cx_ER_IRQn I2C1_ER_IRQn + +/* I2C TIMING Register define when I2C clock source is SYSCLK */ +/* I2C TIMING is calculated from APB1 source clock = 50 MHz */ +/* Due to the big MOFSET capacity for adapting the camera level the rising time is very large (>1us) */ +/* 0x40912732 takes in account the big rising and aims a clock of 100khz */ +#ifndef DISCOVERY_I2Cx_TIMING +#define DISCOVERY_I2Cx_TIMING ((uint32_t)0x40912732) +#endif /* DISCOVERY_I2Cx_TIMING */ + +/** + * @} + */ + +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_LOW_LEVEL_Exported_Macros STM32F7508_DISCOVERY_LOW_LEVEL Exported Macros + * @{ + */ +/** + * @} + */ + +/** @addtogroup STM32F7508_DISCOVERY_LOW_LEVEL_Exported_Functions + * @{ + */ +uint32_t BSP_GetVersion(void); +void BSP_LED_Init(Led_TypeDef Led); +void BSP_LED_DeInit(Led_TypeDef Led); +void BSP_LED_On(Led_TypeDef Led); +void BSP_LED_Off(Led_TypeDef Led); +void BSP_LED_Toggle(Led_TypeDef Led); +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef ButtonMode); +void BSP_PB_DeInit(Button_TypeDef Button); +uint32_t BSP_PB_GetState(Button_TypeDef Button); +void BSP_COM_Init(COM_TypeDef COM, UART_HandleTypeDef *husart); +void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7508_DISCOVERY_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_audio.c b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_audio.c new file mode 100644 index 00000000..2cb86269 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_audio.c @@ -0,0 +1,1364 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_audio.c + * @author MCD Application Team + * @brief This file provides the Audio driver for the STM32F7508-Discovery board. + @verbatim + How To use this driver: + ----------------------- + + This driver supports STM32F7xx devices on STM32F7508-Discovery (MB1191) board. + + Call the function BSP_AUDIO_OUT_Init( + OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, + OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH) + Volume : Initial volume to be set (0 is min (mute), 100 is max (100%) + AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...) + this parameter is relative to the audio file/stream type. + ) + This function configures all the hardware required for the audio application (codec, I2C, SAI, + GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK. + If the returned value is different from AUDIO_OK or the function is stuck then the communication with + the codec or the MFX has failed (try to un-plug the power or reset device in this case). + - OUTPUT_DEVICE_SPEAKER : only speaker will be set as output for the audio stream. + - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream. + - OUTPUT_DEVICE_BOTH : both Speaker and Headphone are used as outputs for the audio stream + at the same time. + Note. On STM32F7508-Discovery SAI_DMA is configured in CIRCULAR mode. Due to this the application + does NOT need to call BSP_AUDIO_OUT_ChangeBuffer() to assure streaming. + + Call the function BSP_DISCOVERY_AUDIO_OUT_Play( + pBuffer: pointer to the audio data file address + Size : size of the buffer to be sent in Bytes + ) + to start playing (for the first time) from the audio file/stream. + + Call the function BSP_AUDIO_OUT_Pause() to pause playing + + Call the function BSP_AUDIO_OUT_Resume() to resume playing. + Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called + for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case). + Note. This function should be called only when the audio file is played or paused (not stopped). + + For each mode, you may need to implement the relative callback functions into your code. + The Callback functions are named AUDIO_OUT_XXX_CallBack() and only their prototypes are declared in + the stm32f7508_discovery_audio.h file. (refer to the example for more details on the callbacks implementations) + + To Stop playing, to modify the volume level, the frequency, the audio frame slot, + the device output mode the mute or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(), + AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetAudioFrameSlot(), BSP_AUDIO_OUT_SetOutputMode(), + BSP_AUDIO_OUT_SetMute() and BSP_AUDIO_OUT_Stop(). + + The driver API and the callback functions are at the end of the stm32f7508_discovery_audio.h file. + + Driver architecture: + -------------------- + + This driver provides the High Audio Layer: consists of the function API exported in the stm32f7508_discovery_audio.h file + (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...) + + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/ + providing the audio file/stream. These functions are also included as local functions into + the stm32f7508_discovery_audio_codec.c file (SAIx_Out_Init() and SAIx_Out_DeInit(), SAIx_In_Init() and SAIx_In_DeInit()) + + Known Limitations: + ------------------ + 1- If the TDM Format used to play in parallel 2 audio Stream (the first Stream is configured in codec SLOT0 and second + Stream in SLOT1) the Pause/Resume, volume and mute feature will control the both streams. + 2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, + File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file. + 3- Supports only Stereo audio streaming. + 4- Supports only 16-bits audio data size. + @endverbatim + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7508_discovery.c +- stm32f7xx_hal_sai.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- wm8994.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7508_discovery_audio.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO STM32F7508_DISCOVERY_AUDIO + * @brief This file includes the low layer driver for wm8994 Audio Codec + * available on STM32F7508-Discovery board(MB1191). + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO_Private_Types STM32F7508_DISCOVERY AUDIO Private Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO_Private_Defines STM32F7508_DISCOVERY AUDIO Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO_Private_Macros STM32F7508_DISCOVERY AUDIO Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO_Private_Variables STM32F7508_DISCOVERY AUDIO Private Variables + * @{ + */ +AUDIO_DrvTypeDef *audio_drv; +SAI_HandleTypeDef haudio_out_sai={0}; +SAI_HandleTypeDef haudio_in_sai={0}; +TIM_HandleTypeDef haudio_tim; + +uint16_t __IO AudioInVolume = DEFAULT_AUDIO_IN_VOLUME; + +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO_Private_Function_Prototypes STM32F7508_DISCOVERY AUDIO Private Function Prototypes + * @{ + */ +static void SAIx_Out_Init(uint32_t AudioFreq); +static void SAIx_Out_DeInit(void); +static void SAIx_In_Init(uint32_t SaiOutMode, uint32_t SlotActive, uint32_t AudioFreq); +static void SAIx_In_DeInit(void); +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO_OUT_Exported_Functions STM32F7508_DISCOVERY AUDIO Out Exported Functions + * @{ + */ + +/** + * @brief Configures the audio peripherals. + * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * or OUTPUT_DEVICE_BOTH. + * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) + * @param AudioFreq: Audio frequency used to play the audio stream. + * @note The I2S PLL input clock must be done in the user application. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + + /* Disable SAI */ + SAIx_Out_DeInit(); + + /* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); + } + SAIx_Out_Init(AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq); + } + + return ret; +} + +/** + * @brief Starts playing audio stream from a data buffer for a determined size. + * @param pBuffer: Pointer to the buffer + * @param Size: Number of audio data in BYTES unit. + * In memory, first element is for left channel, second element is for right channel + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size) +{ + /* Call the audio Codec Play function */ + if(audio_drv->Play(AUDIO_I2C_ADDRESS, pBuffer, Size) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Update the Media layer and enable it for play */ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, DMA_MAX(Size / AUDIODATA_SIZE)); + + return AUDIO_OK; + } +} + +/** + * @brief Sends n-Bytes on the SAI interface. + * @param pData: pointer on data address + * @param Size: number of data to be written + * @retval None + */ +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size) +{ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pData, Size); +} + +/** + * @brief This function Pauses the audio file stream. In case + * of using DMA, the DMA Pause feature is used. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Pause(void) +{ + /* Call the Audio Codec Pause/Resume function */ + if(audio_drv->Pause(AUDIO_I2C_ADDRESS) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause function */ + HAL_SAI_DMAPause(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief This function Resumes the audio file stream. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Resume(void) +{ + /* Call the Audio Codec Pause/Resume function */ + if(audio_drv->Resume(AUDIO_I2C_ADDRESS) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause/resume function */ + HAL_SAI_DMAResume(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Stops audio playing and Power down the Audio Codec. + * @param Option: could be one of the following parameters + * - CODEC_PDWN_SW: for software power off (by writing registers). + * Then no need to reconfigure the Codec after power on. + * - CODEC_PDWN_HW: completely shut down the codec (physically). + * Then need to reconfigure the Codec after power on. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option) +{ + /* Call the Media layer stop function */ + HAL_SAI_DMAStop(&haudio_out_sai); + + /* Call Audio Codec Stop function */ + if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) + { + return AUDIO_ERROR; + } + else + { + if(Option == CODEC_PDWN_HW) + { + /* Wait at least 100us */ + HAL_Delay(1); + } + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Controls the current audio volume level. + * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for + * Mute and 100 for Max volume level). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume) +{ + /* Call the codec volume control function with converted volume value */ + if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Enables or disables the MUTE mode by software + * @param Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to + * unmute the codec and restore previous volume level. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd) +{ + /* Call the Codec Mute function */ + if(audio_drv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Switch dynamically (while audio file is played) the output target + * (speaker or headphone). + * @param Output: The audio output target: OUTPUT_DEVICE_SPEAKER, + * OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output) +{ + /* Call the Codec output device function */ + if(audio_drv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Updates the audio frequency. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frequency. + * @retval None + */ +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq) +{ + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frequency configuration */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Updates the Audio frame slot configuration. + * @param AudioFrameSlot: specifies the audio Frame slot + * This parameter can be one of the following values + * @arg CODEC_AUDIOFRAME_SLOT_0123 + * @arg CODEC_AUDIOFRAME_SLOT_02 + * @arg CODEC_AUDIOFRAME_SLOT_13 + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frame slot. + * @retval None + */ +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot) +{ + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frame slot configuration */ + haudio_out_sai.SlotInit.SlotActive = AudioFrameSlot; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Deinit the audio peripherals. + * @retval None + */ +void BSP_AUDIO_OUT_DeInit(void) +{ + SAIx_Out_DeInit(); + /* DeInit the SAI MSP : this __weak function can be rewritten by the application */ + BSP_AUDIO_OUT_MspDeInit(&haudio_out_sai, NULL); +} + +/** + * @brief Tx Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f7508_discovery_audio.h) */ + BSP_AUDIO_OUT_TransferComplete_CallBack(); +} + +/** + * @brief Tx Half Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f7508_discovery_audio.h) */ + BSP_AUDIO_OUT_HalfTransfer_CallBack(); +} + +/** + * @brief SAI error callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai) +{ + HAL_SAI_StateTypeDef audio_out_state; + HAL_SAI_StateTypeDef audio_in_state; + + audio_out_state = HAL_SAI_GetState(&haudio_out_sai); + audio_in_state = HAL_SAI_GetState(&haudio_in_sai); + + /* Determines if it is an audio out or audio in error */ + if ((audio_out_state == HAL_SAI_STATE_BUSY) || (audio_out_state == HAL_SAI_STATE_BUSY_TX)) + { + BSP_AUDIO_OUT_Error_CallBack(); + } + + if ((audio_in_state == HAL_SAI_STATE_BUSY) || (audio_in_state == HAL_SAI_STATE_BUSY_RX)) + { + BSP_AUDIO_IN_Error_CallBack(); + } +} + +/** + * @brief Manages the DMA full Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void) +{ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void) +{ +} + +/** + * @brief Manages the DMA FIFO error event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_Error_CallBack(void) +{ +} + +/** + * @brief Initializes BSP_AUDIO_OUT MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params) +{ + static DMA_HandleTypeDef hdma_sai_tx; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SAI clock */ + AUDIO_OUT_SAIx_CLK_ENABLE(); + + /* Enable GPIO clock */ + AUDIO_OUT_SAIx_MCLK_ENABLE(); + AUDIO_OUT_SAIx_SCK_SD_ENABLE(); + AUDIO_OUT_SAIx_FS_ENABLE(); + /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/ + gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_OUT_SAIx_FS_SD_MCLK_AF; + HAL_GPIO_Init(AUDIO_OUT_SAIx_FS_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_SCK_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_OUT_SAIx_SCK_AF; + HAL_GPIO_Init(AUDIO_OUT_SAIx_SCK_SD_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_SD_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_OUT_SAIx_FS_SD_MCLK_AF; + HAL_GPIO_Init(AUDIO_OUT_SAIx_SCK_SD_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_OUT_SAIx_FS_SD_MCLK_AF; + HAL_GPIO_Init(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, &gpio_init_structure); + + /* Enable the DMA clock */ + AUDIO_OUT_SAIx_DMAx_CLK_ENABLE(); + + if(hsai->Instance == AUDIO_OUT_SAIx) + { + /* Configure the hdma_saiTx handle parameters */ + hdma_sai_tx.Init.Channel = AUDIO_OUT_SAIx_DMAx_CHANNEL; + hdma_sai_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_sai_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sai_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sai_tx.Init.PeriphDataAlignment = AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE; + hdma_sai_tx.Init.MemDataAlignment = AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE; + hdma_sai_tx.Init.Mode = DMA_CIRCULAR; + hdma_sai_tx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_sai_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + hdma_sai_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sai_tx.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_sai_tx.Init.PeriphBurst = DMA_PBURST_SINGLE; + + hdma_sai_tx.Instance = AUDIO_OUT_SAIx_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsai, hdmatx, hdma_sai_tx); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_tx); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hdma_sai_tx); + } + + /* SAI DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_OUT_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ); +} + +/** + * @brief Deinitializes SAI MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* SAI DMA IRQ Channel deactivation */ + HAL_NVIC_DisableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ); + + if(hsai->Instance == AUDIO_OUT_SAIx) + { + /* Deinitialize the DMA stream */ + HAL_DMA_DeInit(hsai->hdmatx); + } + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(hsai); + + /* Deactives CODEC_SAI pins FS, SCK, MCK and SD by putting them in input mode */ + gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_FS_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_SCK_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_SCK_SD_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_SD_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_SCK_SD_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, gpio_init_structure.Pin); + + /* Disable SAI clock */ + AUDIO_OUT_SAIx_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Clock Config. + * @param hsai: might be required to set audio peripheral predivider if any. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @param Params + * @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params) +{ + RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; + + HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); + + /* Set the PLL configuration according to the audio frequency */ + if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) + { + /* Configure PLLI2S prescalers */ + /* PLLI2S_VCO: VCO_429M + I2S_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 429/2 = 214.5 Mhz + I2S_CLK_x = I2S_CLK(first level)/PLLI2SDIVQ = 214.5/19 = 11.289 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 429; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 2; + rcc_ex_clk_init_struct.PLLI2SDivQ = 19; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + + } + else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K), AUDIO_FREQUENCY_96K */ + { + /* I2S clock config + PLLI2S_VCO: VCO_344M + I2S_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 344/7 = 49.142 Mhz + I2S_CLK_x = I2S_CLK(first level)/PLLI2SDIVQ = 49.142/1 = 49.142 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 344; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 7; + rcc_ex_clk_init_struct.PLLI2SDivQ = 1; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + } +} + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Initializes the output Audio Codec audio interface (SAI). + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @note The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123 + * and user can update this configuration using + * @retval None + */ +static void SAIx_Out_Init(uint32_t AudioFreq) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + haudio_out_sai.Init.AudioMode = SAI_MODEMASTER_TX; + haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLED; + haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; + haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; + haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLED; + haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_out_sai.FrameInit.FrameLength = 64; + haudio_out_sai.FrameInit.ActiveFrameLength = 32; + haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot actives */ + haudio_out_sai.SlotInit.FirstBitOffset = 0; + haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_out_sai.SlotInit.SlotNumber = 4; + haudio_out_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_0123; + + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + + + +/** + * @brief Deinitializes the output Audio Codec audio interface (SAI). + * @retval None + */ +static void SAIx_Out_DeInit(void) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + HAL_SAI_DeInit(&haudio_out_sai); +} + +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO_Out_Private_Functions STM32F7508_DISCOVERY_AUDIO Out Private Functions + * @{ + */ + +/** + * @brief Initializes wave recording. + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @param BitRes: Audio frequency to be configured. + * @param ChnlNbr: Channel number. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + return BSP_AUDIO_IN_InitEx(INPUT_DEVICE_DIGITAL_MICROPHONE_2, AudioFreq, BitRes, ChnlNbr); +} + +/** + * @brief Initializes wave recording. + * @param InputDevice: INPUT_DEVICE_DIGITAL_MICROPHONE_2 or INPUT_DEVICE_INPUT_LINE_1 + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @param BitRes: Audio frequency to be configured. + * @param ChnlNbr: Channel number. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + uint32_t slot_active; + + if ((InputDevice != INPUT_DEVICE_INPUT_LINE_1) && /* Only INPUT_LINE_1 and MICROPHONE_2 inputs supported */ + (InputDevice != INPUT_DEVICE_DIGITAL_MICROPHONE_2)) + { + ret = AUDIO_ERROR; + } + else + { + /* Disable SAI */ + SAIx_In_DeInit(); + + /* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_in_sai, AudioFreq, NULL); /* Clock config is shared between AUDIO IN and OUT */ + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from SAI peripheral to memory */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + if(HAL_SAI_GetState(&haudio_in_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_in_sai, NULL); /* Initialize GPIOs for SAI2 block A Master signals */ + BSP_AUDIO_IN_MspInit(&haudio_in_sai, NULL); + } + + /* Configure SAI in master RX mode : + * - SAI2_block_A in master RX mode + * - SAI2_block_B in slave RX mode synchronous from SAI2_block_A + */ + if (InputDevice == INPUT_DEVICE_DIGITAL_MICROPHONE_2) + { + slot_active = CODEC_AUDIOFRAME_SLOT_13; + } + else + { + slot_active = CODEC_AUDIOFRAME_SLOT_02; + } + SAIx_In_Init(SAI_MODEMASTER_RX, slot_active, AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, InputDevice, 100, AudioFreq); + } + } + return ret; +} + +/** + * @brief Initializes wave recording and playback in parallel. + * @param InputDevice: INPUT_DEVICE_DIGITAL_MICROPHONE_2 + * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * or OUTPUT_DEVICE_BOTH. + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @param BitRes: Audio frequency to be configured. + * @param ChnlNbr: Channel number. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_OUT_Init(uint16_t InputDevice, uint16_t OutputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + uint32_t slot_active; + + if (InputDevice != INPUT_DEVICE_DIGITAL_MICROPHONE_2) /* Only MICROPHONE_2 input supported */ + { + ret = AUDIO_ERROR; + } + else + { + /* Disable SAI */ + SAIx_In_DeInit(); + SAIx_Out_DeInit(); + + /* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_in_sai, AudioFreq, NULL); /* Clock config is shared between AUDIO IN and OUT */ + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from SAI peripheral to memory */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + if(HAL_SAI_GetState(&haudio_in_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_IN_MspInit(&haudio_in_sai, NULL); + } + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); + } + + /* Configure SAI in master mode : + * - SAI2_block_A in master TX mode + * - SAI2_block_B in slave RX mode synchronous from SAI2_block_A + */ + if (InputDevice == INPUT_DEVICE_DIGITAL_MICROPHONE_2) + { + slot_active = CODEC_AUDIOFRAME_SLOT_13; + } + else + { + slot_active = CODEC_AUDIOFRAME_SLOT_02; + } + SAIx_In_Init(SAI_MODEMASTER_TX, slot_active, AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, InputDevice | OutputDevice, 100, AudioFreq); + } + } + return ret; +} + + +/** + * @brief Starts audio recording. + * @param pbuf: Main buffer pointer for the recorded data storing + * @param size: size of the recorded buffer in number of elements (typically number of half-words) + * Be careful that it is not the same unit than BSP_AUDIO_OUT_Play function + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size) +{ + uint32_t ret = AUDIO_ERROR; + + /* Start the process receive DMA */ + HAL_SAI_Receive_DMA(&haudio_in_sai, (uint8_t*)pbuf, size); + + /* Return AUDIO_OK when all operations are correctly done */ + ret = AUDIO_OK; + + return ret; +} + +/** + * @brief Stops audio recording. + * @param Option: could be one of the following parameters + * - CODEC_PDWN_SW: for software power off (by writing registers). + * Then no need to reconfigure the Codec after power on. + * - CODEC_PDWN_HW: completely shut down the codec (physically). + * Then need to reconfigure the Codec after power on. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Stop(uint32_t Option) +{ + /* Call the Media layer stop function */ + HAL_SAI_DMAStop(&haudio_in_sai); + + /* Call Audio Codec Stop function */ + if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) + { + return AUDIO_ERROR; + } + else + { + if(Option == CODEC_PDWN_HW) + { + /* Wait at least 100us */ + HAL_Delay(1); + } + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Pauses the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Pause(void) +{ + /* Call the Media layer pause function */ + HAL_SAI_DMAPause(&haudio_in_sai); + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Resumes the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Resume(void) +{ + /* Call the Media layer pause/resume function */ + HAL_SAI_DMAResume(&haudio_in_sai); + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Controls the audio in volume level. + * @param Volume: Volume level in range 0(Mute)..80(+0dB)..100(+17.625dB) + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume) +{ + /* Call the codec volume control function with converted volume value */ + if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Set the Global variable AudioInVolume */ + AudioInVolume = Volume; + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Deinit the audio IN peripherals. + * @retval None + */ +void BSP_AUDIO_IN_DeInit(void) +{ + SAIx_In_DeInit(); + /* DeInit the SAI MSP : this __weak function can be rewritten by the application */ + BSP_AUDIO_IN_MspDeInit(&haudio_in_sai, NULL); +} + + /** + * @brief Rx Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ + BSP_AUDIO_IN_TransferComplete_CallBack(); +} + +/** + * @brief Rx Half Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f7508_discovery_audio.h) */ + BSP_AUDIO_IN_HalfTransfer_CallBack(); +} + +/** + * @brief User callback when record buffer is filled. + * @retval None + */ +__weak void BSP_AUDIO_IN_TransferComplete_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Audio IN Error callback function. + * @retval None + */ +__weak void BSP_AUDIO_IN_Error_CallBack(void) +{ + /* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +} + +/** + * @brief Initializes BSP_AUDIO_IN MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_IN_MspInit(SAI_HandleTypeDef *hsai, void *Params) +{ + static DMA_HandleTypeDef hdma_sai_rx; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SAI clock */ + AUDIO_IN_SAIx_CLK_ENABLE(); + + /* Enable SD GPIO clock */ + AUDIO_IN_SAIx_SD_ENABLE(); + /* CODEC_SAI pin configuration: SD pin */ + gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = AUDIO_IN_SAIx_SD_AF; + HAL_GPIO_Init(AUDIO_IN_SAIx_SD_GPIO_PORT, &gpio_init_structure); + + /* Enable Audio INT GPIO clock */ + AUDIO_IN_INT_GPIO_ENABLE(); + /* Audio INT pin configuration: input */ + gpio_init_structure.Pin = AUDIO_IN_INT_GPIO_PIN; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + HAL_GPIO_Init(AUDIO_IN_INT_GPIO_PORT, &gpio_init_structure); + + /* Enable the DMA clock */ + AUDIO_IN_SAIx_DMAx_CLK_ENABLE(); + + if(hsai->Instance == AUDIO_IN_SAIx) + { + /* Configure the hdma_sai_rx handle parameters */ + hdma_sai_rx.Init.Channel = AUDIO_IN_SAIx_DMAx_CHANNEL; + hdma_sai_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_sai_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sai_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sai_rx.Init.PeriphDataAlignment = AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE; + hdma_sai_rx.Init.MemDataAlignment = AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE; + hdma_sai_rx.Init.Mode = DMA_CIRCULAR; + hdma_sai_rx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_sai_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_sai_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sai_rx.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_sai_rx.Init.PeriphBurst = DMA_MBURST_SINGLE; + + hdma_sai_rx.Instance = AUDIO_IN_SAIx_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsai, hdmarx, hdma_sai_rx); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_rx); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hdma_sai_rx); + } + + /* SAI DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_IN_SAIx_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_IN_SAIx_DMAx_IRQ); + + /* Audio INT IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_IN_INT_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_IN_INT_IRQ); +} + +/** + * @brief DeInitializes BSP_AUDIO_IN MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_IN_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + static DMA_HandleTypeDef hdma_sai_rx; + + /* SAI IN DMA IRQ Channel deactivation */ + HAL_NVIC_DisableIRQ(AUDIO_IN_SAIx_DMAx_IRQ); + + if(hsai->Instance == AUDIO_IN_SAIx) + { + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_rx); + } + + /* Disable SAI block */ + __HAL_SAI_DISABLE(hsai); + + /* Disable pin: SD pin */ + gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN; + HAL_GPIO_DeInit(AUDIO_IN_SAIx_SD_GPIO_PORT, gpio_init_structure.Pin); + + /* Disable SAI clock */ + AUDIO_IN_SAIx_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Initializes the input Audio Codec audio interface (SAI). + * @param SaiOutMode: SAI_MODEMASTER_TX (for record and playback in parallel) + * or SAI_MODEMASTER_RX (for record only). + * @param SlotActive: CODEC_AUDIOFRAME_SLOT_02 or CODEC_AUDIOFRAME_SLOT_13 + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @retval None + */ +static void SAIx_In_Init(uint32_t SaiOutMode, uint32_t SlotActive, uint32_t AudioFreq) +{ + /* Initialize SAI2 block A in MASTER RX */ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + haudio_out_sai.Init.AudioMode = SaiOutMode; + haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLED; + haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; + haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; + haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLED; + haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_out_sai.FrameInit.FrameLength = 64; + haudio_out_sai.FrameInit.ActiveFrameLength = 32; + haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot actives */ + haudio_out_sai.SlotInit.FirstBitOffset = 0; + haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_out_sai.SlotInit.SlotNumber = 4; + haudio_out_sai.SlotInit.SlotActive = SlotActive; + + HAL_SAI_Init(&haudio_out_sai); + + /* Initialize SAI2 block B in SLAVE RX synchronous from SAI2 block A */ + /* Initialize the haudio_in_sai Instance parameter */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_in_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_in_sai.Init.AudioFrequency = AudioFreq; + haudio_in_sai.Init.AudioMode = SAI_MODESLAVE_RX; + haudio_in_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLED; + haudio_in_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_in_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_in_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_in_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; + haudio_in_sai.Init.Synchro = SAI_SYNCHRONOUS; + haudio_in_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLED; + haudio_in_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_in_sai.FrameInit.FrameLength = 64; + haudio_in_sai.FrameInit.ActiveFrameLength = 32; + haudio_in_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_in_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_in_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot active */ + haudio_in_sai.SlotInit.FirstBitOffset = 0; + haudio_in_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_in_sai.SlotInit.SlotNumber = 4; + haudio_in_sai.SlotInit.SlotActive = SlotActive; + + HAL_SAI_Init(&haudio_in_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); + + /* Enable SAI peripheral */ + __HAL_SAI_ENABLE(&haudio_in_sai); +} + + + +/** + * @brief Deinitializes the output Audio Codec audio interface (SAI). + * @retval None + */ +static void SAIx_In_DeInit(void) +{ + /* Initialize the haudio_in_sai Instance parameter */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(&haudio_in_sai); + + HAL_SAI_DeInit(&haudio_in_sai); +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_audio.h b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_audio.h new file mode 100644 index 00000000..d7e89bc0 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_audio.h @@ -0,0 +1,277 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_audio.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f7508_discovery_audio.c driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7508_DISCOVERY_AUDIO_H +#define __STM32F7508_DISCOVERY_AUDIO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include audio component Driver */ +#include "../Components/wm8994/wm8994.h" +#include "stm32f7508_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO STM32F7508_DISCOVERY_AUDIO + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO_Exported_Types STM32F7508_DISCOVERY_AUDIO Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO_Exported_Constants STM32F7508_DISCOVERY_AUDIO Exported Constants + * @{ + */ + +/*------------------------------------------------------------------------------ + USER SAI defines parameters + -----------------------------------------------------------------------------*/ +/* CODEC_AudioFrame_SLOT_TDMMode + In W8994 codec the Audio frame contains 4 slots : TDM Mode + TDM format : + +------------------|------------------|--------------------|-------------------+ + | CODEC_SLOT0 Left | CODEC_SLOT1 Left | CODEC_SLOT0 Right | CODEC_SLOT1 Right | + +------------------------------------------------------------------------------+ + */ +/* To have 2 separate audio stream in Both headphone and speaker the 4 slot must be activated */ +#define CODEC_AUDIOFRAME_SLOT_0123 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_2 | SAI_SLOTACTIVE_3 +/* To have an audio stream in headphone only SAI Slot 0 and Slot 2 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_02 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_2 +/* To have an audio stream in speaker only SAI Slot 1 and Slot 3 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_13 SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_3 + +/* SAI OUT peripheral configuration defines */ +#define AUDIO_OUT_SAIx SAI2_Block_A +#define AUDIO_OUT_SAIx_CLK_ENABLE() __HAL_RCC_SAI2_CLK_ENABLE() +#define AUDIO_OUT_SAIx_CLK_DISABLE() __HAL_RCC_SAI2_CLK_DISABLE() +#define AUDIO_OUT_SAIx_SCK_AF GPIO_AF10_SAI2 +#define AUDIO_OUT_SAIx_FS_SD_MCLK_AF GPIO_AF10_SAI2 + +#define AUDIO_OUT_SAIx_MCLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define AUDIO_OUT_SAIx_MCLK_GPIO_PORT GPIOI +#define AUDIO_OUT_SAIx_MCLK_PIN GPIO_PIN_4 +#define AUDIO_OUT_SAIx_SCK_SD_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define AUDIO_OUT_SAIx_SCK_SD_GPIO_PORT GPIOI +#define AUDIO_OUT_SAIx_SCK_PIN GPIO_PIN_5 +#define AUDIO_OUT_SAIx_SD_PIN GPIO_PIN_6 +#define AUDIO_OUT_SAIx_FS_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define AUDIO_OUT_SAIx_FS_GPIO_PORT GPIOI +#define AUDIO_OUT_SAIx_FS_PIN GPIO_PIN_7 + +/* SAI DMA Stream definitions */ +#define AUDIO_OUT_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_OUT_SAIx_DMAx_STREAM DMA2_Stream4 +#define AUDIO_OUT_SAIx_DMAx_CHANNEL DMA_CHANNEL_3 +#define AUDIO_OUT_SAIx_DMAx_IRQ DMA2_Stream4_IRQn +#define AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD +#define AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD +#define DMA_MAX_SZE ((uint16_t)0xFFFF) + +#define AUDIO_OUT_SAIx_DMAx_IRQHandler DMA2_Stream4_IRQHandler + +/* Select the interrupt preemption priority for the DMA interrupt */ +#define AUDIO_OUT_IRQ_PREPRIO ((uint32_t)0x0E) /* Select the preemption priority level(0 is the highest) */ + +/*------------------------------------------------------------------------------ + AUDIO IN CONFIGURATION +------------------------------------------------------------------------------*/ +/* SAI IN peripheral configuration defines */ +#define AUDIO_IN_SAIx SAI2_Block_B +#define AUDIO_IN_SAIx_CLK_ENABLE() __HAL_RCC_SAI2_CLK_ENABLE() +#define AUDIO_IN_SAIx_CLK_DISABLE() __HAL_RCC_SAI2_CLK_DISABLE() +#define AUDIO_IN_SAIx_SD_AF GPIO_AF10_SAI2 + +#define AUDIO_IN_SAIx_SD_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE() +#define AUDIO_IN_SAIx_SD_GPIO_PORT GPIOG +#define AUDIO_IN_SAIx_SD_PIN GPIO_PIN_10 + +#define AUDIO_IN_INT_GPIO_ENABLE() __HAL_RCC_GPIOH_CLK_ENABLE() +#define AUDIO_IN_INT_GPIO_PORT GPIOH +#define AUDIO_IN_INT_GPIO_PIN GPIO_PIN_15 +#define AUDIO_IN_INT_IRQ EXTI15_10_IRQn + +/* SAI DMA Stream definitions */ +#define AUDIO_IN_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_IN_SAIx_DMAx_STREAM DMA2_Stream7 +#define AUDIO_IN_SAIx_DMAx_CHANNEL DMA_CHANNEL_0 +#define AUDIO_IN_SAIx_DMAx_IRQ DMA2_Stream7_IRQn +#define AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD +#define AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD + +#define AUDIO_IN_SAIx_DMAx_IRQHandler DMA2_Stream7_IRQHandler +#define AUDIO_IN_INT_IRQHandler EXTI15_10_IRQHandler + +/* Select the interrupt preemption priority and subpriority for the IT/DMA interrupt */ +#define AUDIO_IN_IRQ_PREPRIO ((uint32_t)0x0F) /* Select the preemption priority level(0 is the highest) */ + +/*------------------------------------------------------------------------------ + CONFIGURATION: Audio Driver Configuration parameters +------------------------------------------------------------------------------*/ + +#define AUDIODATA_SIZE ((uint16_t)2) /* 16-bits audio data size */ + +/* Audio status definition */ +#define AUDIO_OK ((uint8_t)0) +#define AUDIO_ERROR ((uint8_t)1) +#define AUDIO_TIMEOUT ((uint8_t)2) + +/* AudioFreq * DataSize (2 bytes) * NumChannels (Stereo: 2) */ +#define DEFAULT_AUDIO_IN_FREQ I2S_AUDIOFREQ_16K +#define DEFAULT_AUDIO_IN_BIT_RESOLUTION ((uint8_t)16) +#define DEFAULT_AUDIO_IN_CHANNEL_NBR ((uint8_t)2) /* Mono = 1, Stereo = 2 */ +#define DEFAULT_AUDIO_IN_VOLUME ((uint16_t)64) + +/*------------------------------------------------------------------------------ + OPTIONAL Configuration defines parameters +------------------------------------------------------------------------------*/ + +/* Delay for the Codec to be correctly reset */ +#define CODEC_RESET_DELAY ((uint8_t)5) + + +/*------------------------------------------------------------------------------ + OUTPUT DEVICES definition +------------------------------------------------------------------------------*/ +/* Alias on existing output devices to adapt for 2 headphones output */ +#define OUTPUT_DEVICE_HEADPHONE1 OUTPUT_DEVICE_HEADPHONE +#define OUTPUT_DEVICE_HEADPHONE2 OUTPUT_DEVICE_SPEAKER /* Headphone2 is connected to Speaker output of the wm8994 */ + +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO_Exported_Variables STM32F7508_DISCOVERY_AUDIO Exported Variables + * @{ + */ +extern __IO uint16_t AudioInVolume; + /** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO_Exported_Macros STM32F7508_DISCOVERY_AUDIO Exported Macros + * @{ + */ +#define DMA_MAX(x) (((x) <= DMA_MAX_SZE)? (x):DMA_MAX_SZE) +/** + * @} + */ + +/** @addtogroup STM32F7508_DISCOVERY_AUDIO_OUT_Exported_Functions + * @{ + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq); +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size); +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size); +uint8_t BSP_AUDIO_OUT_Pause(void); +uint8_t BSP_AUDIO_OUT_Resume(void); +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option); +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume); +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq); +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot); +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd); +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output); +void BSP_AUDIO_OUT_DeInit(void); + +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function is called when the requested data has been completely transferred.*/ +void BSP_AUDIO_OUT_TransferComplete_CallBack(void); + +/* This function is called when half of the requested buffer has been transferred. */ +void BSP_AUDIO_OUT_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_OUT_Error_CallBack(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params); +void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params); +void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); + +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_AUDIO_IN_Exported_Functions STM32F7508_DISCOVERY_AUDIO_IN Exported Functions + * @{ + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_OUT_Init(uint16_t InputDevice, uint16_t OutputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_Record(uint16_t *pData, uint32_t Size); +uint8_t BSP_AUDIO_IN_Stop(uint32_t Option); +uint8_t BSP_AUDIO_IN_Pause(void); +uint8_t BSP_AUDIO_IN_Resume(void); +uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume); +void BSP_AUDIO_IN_DeInit(void); +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled to prepare the next + buffer pointer and its size. */ +void BSP_AUDIO_IN_TransferComplete_CallBack(void); +void BSP_AUDIO_IN_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_IN_Error_CallBack(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_IN_MspInit(SAI_HandleTypeDef *hsai, void *Params); +void BSP_AUDIO_IN_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7508_DISCOVERY_AUDIO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_camera.c b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_camera.c new file mode 100644 index 00000000..35a6f8b9 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_camera.c @@ -0,0 +1,643 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_camera.c + * @author MCD Application Team + * @brief This file includes the driver for Camera modules mounted on + * STM32F7508-Discovery board. + @verbatim + How to use this driver: + ------------------------ + - This driver is used to drive the camera. + - The OV9655 component driver MUST be included with this driver. + + Driver description: + ------------------- + + Initialization steps: + o Initialize the camera using the BSP_CAMERA_Init() function. + o Start the camera capture/snapshot using the CAMERA_Start() function. + o Suspend, resume or stop the camera capture using the following functions: + - BSP_CAMERA_Suspend() + - BSP_CAMERA_Resume() + - BSP_CAMERA_Stop() + + + Options + o Increase or decrease on the fly the brightness and/or contrast + using the following function: + - BSP_CAMERA_ContrastBrightnessConfig + o Add a special effect on the fly using the following functions: + - BSP_CAMERA_BlackWhiteConfig() + - BSP_CAMERA_ColorEffectConfig() + @endverbatim + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7508_discovery.c +- stm32f7xx_hal_dcmi.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- ov9655.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7508_discovery_camera.h" +#include "stm32f7508_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY_CAMERA + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_CAMERA_Private_TypesDefinitions STM32F7508_DISCOVERY_CAMERA Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_CAMERA_Private_Defines STM32F7508_DISCOVERY_CAMERA Private Defines + * @{ + */ +#define CAMERA_VGA_RES_X 640 +#define CAMERA_VGA_RES_Y 480 +#define CAMERA_480x272_RES_X 480 +#define CAMERA_480x272_RES_Y 272 +#define CAMERA_QVGA_RES_X 320 +#define CAMERA_QVGA_RES_Y 240 +#define CAMERA_QQVGA_RES_X 160 +#define CAMERA_QQVGA_RES_Y 120 +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_CAMERA_Private_Macros STM32F7508_DISCOVERY_CAMERA Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_CAMERA_Private_Variables STM32F7508_DISCOVERY_CAMERA Private Variables + * @{ + */ +DCMI_HandleTypeDef hDcmiHandler; +CAMERA_DrvTypeDef *camera_drv; +/* Camera current resolution naming (QQVGA, VGA, ...) */ +static uint32_t CameraCurrentResolution; + +/* Camera module I2C HW address */ +static uint32_t CameraHwAddress; +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_CAMERA_Private_FunctionPrototypes STM32F7508_DISCOVERY_CAMERA Private Function Prototypes + * @{ + */ +static uint32_t GetSize(uint32_t resolution); +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_CAMERA_Exported_Functions STM32F7508_DISCOVERY_CAMERA Exported Functions + * @{ + */ + +/** + * @brief Initializes the camera. + * @param Resolution : camera sensor requested resolution (x, y) : standard resolution + * naming QQVGA, QVGA, VGA ... + * @retval Camera status + */ +uint8_t BSP_CAMERA_Init(uint32_t Resolution) +{ + DCMI_HandleTypeDef *phdcmi; + uint8_t status = CAMERA_ERROR; + + /* Get the DCMI handle structure */ + phdcmi = &hDcmiHandler; + + /*** Configures the DCMI to interface with the camera module ***/ + /* DCMI configuration */ + phdcmi->Init.CaptureRate = DCMI_CR_ALL_FRAME; + phdcmi->Init.HSPolarity = DCMI_HSPOLARITY_LOW; + phdcmi->Init.SynchroMode = DCMI_SYNCHRO_HARDWARE; + phdcmi->Init.VSPolarity = DCMI_VSPOLARITY_HIGH; + phdcmi->Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B; + phdcmi->Init.PCKPolarity = DCMI_PCKPOLARITY_RISING; + phdcmi->Instance = DCMI; + + /* Power up camera */ + BSP_CAMERA_PwrUp(); + + /* Read ID of Camera module via I2C */ + if(ov9655_ReadID(CAMERA_I2C_ADDRESS) == OV9655_ID) + { + /* Initialize the camera driver structure */ + camera_drv = &ov9655_drv; + CameraHwAddress = CAMERA_I2C_ADDRESS; + + /* DCMI Initialization */ + BSP_CAMERA_MspInit(&hDcmiHandler, NULL); + HAL_DCMI_Init(phdcmi); + + /* Camera Module Initialization via I2C to the wanted 'Resolution' */ + if (Resolution == CAMERA_R480x272) + { /* For 480x272 resolution, the OV9655 sensor is set to VGA resolution + * as OV9655 doesn't supports 480x272 resolution, + * then DCMI is configured to output a 480x272 cropped window */ + camera_drv->Init(CameraHwAddress, CAMERA_R640x480); + HAL_DCMI_ConfigCROP(phdcmi, /* Crop in the middle of the VGA picture */ + (CAMERA_VGA_RES_X - CAMERA_480x272_RES_X)/2, + (CAMERA_VGA_RES_Y - CAMERA_480x272_RES_Y)/2, + (CAMERA_480x272_RES_X * 2) - 1, + CAMERA_480x272_RES_Y - 1); + HAL_DCMI_EnableCROP(phdcmi); + } + else + { + camera_drv->Init(CameraHwAddress, Resolution); + HAL_DCMI_DisableCROP(phdcmi); + } + + CameraCurrentResolution = Resolution; + + /* Return CAMERA_OK status */ + status = CAMERA_OK; + } + else + { + /* Return CAMERA_NOT_SUPPORTED status */ + status = CAMERA_NOT_SUPPORTED; + } + + return status; +} + +/** + * @brief DeInitializes the camera. + * @retval Camera status + */ +uint8_t BSP_CAMERA_DeInit(void) +{ + hDcmiHandler.Instance = DCMI; + + HAL_DCMI_DeInit(&hDcmiHandler); + BSP_CAMERA_MspDeInit(&hDcmiHandler, NULL); + return CAMERA_OK; +} + +/** + * @brief Starts the camera capture in continuous mode. + * @param buff: pointer to the camera output buffer + * @retval None + */ +void BSP_CAMERA_ContinuousStart(uint8_t *buff) +{ + /* Start the camera capture */ + HAL_DCMI_Start_DMA(&hDcmiHandler, DCMI_MODE_CONTINUOUS, (uint32_t)buff, GetSize(CameraCurrentResolution)); +} + +/** + * @brief Starts the camera capture in snapshot mode. + * @param buff: pointer to the camera output buffer + * @retval None + */ +void BSP_CAMERA_SnapshotStart(uint8_t *buff) +{ + /* Start the camera capture */ + HAL_DCMI_Start_DMA(&hDcmiHandler, DCMI_MODE_SNAPSHOT, (uint32_t)buff, GetSize(CameraCurrentResolution)); +} + +/** + * @brief Suspend the CAMERA capture + * @retval None + */ +void BSP_CAMERA_Suspend(void) +{ + /* Suspend the Camera Capture */ + HAL_DCMI_Suspend(&hDcmiHandler); +} + +/** + * @brief Resume the CAMERA capture + * @retval None + */ +void BSP_CAMERA_Resume(void) +{ + /* Start the Camera Capture */ + HAL_DCMI_Resume(&hDcmiHandler); +} + +/** + * @brief Stop the CAMERA capture + * @retval Camera status + */ +uint8_t BSP_CAMERA_Stop(void) +{ + uint8_t status = CAMERA_ERROR; + + if(HAL_DCMI_Stop(&hDcmiHandler) == HAL_OK) + { + status = CAMERA_OK; + } + + /* Set Camera in Power Down */ + BSP_CAMERA_PwrDown(); + + return status; +} + +/** + * @brief CANERA power up + * @retval None + */ +void BSP_CAMERA_PwrUp(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable GPIO clock */ + __HAL_RCC_GPIOH_CLK_ENABLE(); + + /*** Configure the GPIO ***/ + /* Configure DCMI GPIO as alternate function */ + gpio_init_structure.Pin = GPIO_PIN_13; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(GPIOH, &gpio_init_structure); + + /* De-assert the camera POWER_DOWN pin (active high) */ + HAL_GPIO_WritePin(GPIOH, GPIO_PIN_13, GPIO_PIN_RESET); + + HAL_Delay(3); /* POWER_DOWN de-asserted during 3ms */ +} + +/** + * @brief CAMERA power down + * @retval None + */ +void BSP_CAMERA_PwrDown(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable GPIO clock */ + __HAL_RCC_GPIOH_CLK_ENABLE(); + + /*** Configure the GPIO ***/ + /* Configure DCMI GPIO as alternate function */ + gpio_init_structure.Pin = GPIO_PIN_13; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(GPIOH, &gpio_init_structure); + + /* Assert the camera POWER_DOWN pin (active high) */ + HAL_GPIO_WritePin(GPIOH, GPIO_PIN_13, GPIO_PIN_SET); +} + +/** + * @brief Configures the camera contrast and brightness. + * @param contrast_level: Contrast level + * This parameter can be one of the following values: + * @arg CAMERA_CONTRAST_LEVEL4: for contrast +2 + * @arg CAMERA_CONTRAST_LEVEL3: for contrast +1 + * @arg CAMERA_CONTRAST_LEVEL2: for contrast 0 + * @arg CAMERA_CONTRAST_LEVEL1: for contrast -1 + * @arg CAMERA_CONTRAST_LEVEL0: for contrast -2 + * @param brightness_level: Contrast level + * This parameter can be one of the following values: + * @arg CAMERA_BRIGHTNESS_LEVEL4: for brightness +2 + * @arg CAMERA_BRIGHTNESS_LEVEL3: for brightness +1 + * @arg CAMERA_BRIGHTNESS_LEVEL2: for brightness 0 + * @arg CAMERA_BRIGHTNESS_LEVEL1: for brightness -1 + * @arg CAMERA_BRIGHTNESS_LEVEL0: for brightness -2 + * @retval None + */ +void BSP_CAMERA_ContrastBrightnessConfig(uint32_t contrast_level, uint32_t brightness_level) +{ + if(camera_drv->Config != NULL) + { + camera_drv->Config(CameraHwAddress, CAMERA_CONTRAST_BRIGHTNESS, contrast_level, brightness_level); + } +} + +/** + * @brief Configures the camera white balance. + * @param Mode: black_white mode + * This parameter can be one of the following values: + * @arg CAMERA_BLACK_WHITE_BW + * @arg CAMERA_BLACK_WHITE_NEGATIVE + * @arg CAMERA_BLACK_WHITE_BW_NEGATIVE + * @arg CAMERA_BLACK_WHITE_NORMAL + * @retval None + */ +void BSP_CAMERA_BlackWhiteConfig(uint32_t Mode) +{ + if(camera_drv->Config != NULL) + { + camera_drv->Config(CameraHwAddress, CAMERA_BLACK_WHITE, Mode, 0); + } +} + +/** + * @brief Configures the camera color effect. + * @param Effect: Color effect + * This parameter can be one of the following values: + * @arg CAMERA_COLOR_EFFECT_ANTIQUE + * @arg CAMERA_COLOR_EFFECT_BLUE + * @arg CAMERA_COLOR_EFFECT_GREEN + * @arg CAMERA_COLOR_EFFECT_RED + * @retval None + */ +void BSP_CAMERA_ColorEffectConfig(uint32_t Effect) +{ + if(camera_drv->Config != NULL) + { + camera_drv->Config(CameraHwAddress, CAMERA_COLOR_EFFECT, Effect, 0); + } +} + +/** + * @brief Get the capture size in pixels unit. + * @param resolution: the current resolution. + * @retval capture size in pixels unit. + */ +static uint32_t GetSize(uint32_t resolution) +{ + uint32_t size = 0; + + /* Get capture size */ + switch (resolution) + { + case CAMERA_R160x120: + { + size = 0x2580; + } + break; + case CAMERA_R320x240: + { + size = 0x9600; + } + break; + case CAMERA_R480x272: + { + size = 0xFF00; + } + break; + case CAMERA_R640x480: + { + size = 0x25800; + } + break; + default: + { + break; + } + } + + return size; +} + +/** + * @brief Initializes the DCMI MSP. + * @param hdcmi: HDMI handle + * @param Params + * @retval None + */ +__weak void BSP_CAMERA_MspInit(DCMI_HandleTypeDef *hdcmi, void *Params) +{ + static DMA_HandleTypeDef hdma_handler; + GPIO_InitTypeDef gpio_init_structure; + + /*** Enable peripherals and GPIO clocks ***/ + /* Enable DCMI clock */ + __HAL_RCC_DCMI_CLK_ENABLE(); + + /* Enable DMA2 clock */ + __HAL_RCC_DMA2_CLK_ENABLE(); + + /* Enable GPIO clocks */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + + /*** Configure the GPIO ***/ + /* Configure DCMI GPIO as alternate function */ + gpio_init_structure.Pin = GPIO_PIN_4 | GPIO_PIN_6; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOA, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_3; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_5 | GPIO_PIN_6; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_9; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 |\ + GPIO_PIN_12 | GPIO_PIN_14; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOH, &gpio_init_structure); + + /*** Configure the DMA ***/ + /* Set the parameters to be configured */ + hdma_handler.Init.Channel = DMA_CHANNEL_1; + hdma_handler.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_handler.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_handler.Init.MemInc = DMA_MINC_ENABLE; + hdma_handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + hdma_handler.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + hdma_handler.Init.Mode = DMA_CIRCULAR; + hdma_handler.Init.Priority = DMA_PRIORITY_HIGH; + hdma_handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_handler.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_handler.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_handler.Init.PeriphBurst = DMA_PBURST_SINGLE; + + hdma_handler.Instance = DMA2_Stream1; + + /* Associate the initialized DMA handle to the DCMI handle */ + __HAL_LINKDMA(hdcmi, DMA_Handle, hdma_handler); + + /*** Configure the NVIC for DCMI and DMA ***/ + /* NVIC configuration for DCMI transfer complete interrupt */ + HAL_NVIC_SetPriority(DCMI_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DCMI_IRQn); + + /* NVIC configuration for DMA2D transfer complete interrupt */ + HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn); + + /* Configure the DMA stream */ + HAL_DMA_Init(hdcmi->DMA_Handle); +} + + +/** + * @brief DeInitializes the DCMI MSP. + * @param hdcmi: HDMI handle + * @param Params + * @retval None + */ +__weak void BSP_CAMERA_MspDeInit(DCMI_HandleTypeDef *hdcmi, void *Params) +{ + /* Disable NVIC for DCMI transfer complete interrupt */ + HAL_NVIC_DisableIRQ(DCMI_IRQn); + + /* Disable NVIC for DMA2 transfer complete interrupt */ + HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn); + + /* Configure the DMA stream */ + HAL_DMA_DeInit(hdcmi->DMA_Handle); + + /* Disable DCMI clock */ + __HAL_RCC_DCMI_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Line event callback + * @param hdcmi: pointer to the DCMI handle + * @retval None + */ +void HAL_DCMI_LineEventCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_LineEventCallback(); +} + +/** + * @brief Line Event callback. + * @retval None + */ +__weak void BSP_CAMERA_LineEventCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_LineEventCallback could be implemented in the user file + */ +} + +/** + * @brief VSYNC event callback + * @param hdcmi: pointer to the DCMI handle + * @retval None + */ +void HAL_DCMI_VsyncEventCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_VsyncEventCallback(); +} + +/** + * @brief VSYNC Event callback. + * @retval None + */ +__weak void BSP_CAMERA_VsyncEventCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_VsyncEventCallback could be implemented in the user file + */ +} + +/** + * @brief Frame event callback + * @param hdcmi: pointer to the DCMI handle + * @retval None + */ +void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_FrameEventCallback(); +} + +/** + * @brief Frame Event callback. + * @retval None + */ +__weak void BSP_CAMERA_FrameEventCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_FrameEventCallback could be implemented in the user file + */ +} + +/** + * @brief Error callback + * @param hdcmi: pointer to the DCMI handle + * @retval None + */ +void HAL_DCMI_ErrorCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_ErrorCallback(); +} + +/** + * @brief Error callback. + * @retval None + */ +__weak void BSP_CAMERA_ErrorCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_ErrorCallback could be implemented in the user file + */ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_camera.h b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_camera.h new file mode 100644 index 00000000..56d5350f --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_camera.h @@ -0,0 +1,131 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_camera.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f7508_discovery_camera.c driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7508_DISCOVERY_CAMERA_H +#define __STM32F7508_DISCOVERY_CAMERA_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include Camera component Driver */ +#include "../Components/ov9655/ov9655.h" +#include "stm32f7508_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY_CAMERA + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_CAMERA_Exported_Types STM32F7508_DISCOVERY_CAMERA Exported Types + * @{ + */ + +/** + * @brief Camera State structures definition + */ +typedef enum +{ + CAMERA_OK = 0x00, + CAMERA_ERROR = 0x01, + CAMERA_TIMEOUT = 0x02, + CAMERA_NOT_DETECTED = 0x03, + CAMERA_NOT_SUPPORTED = 0x04 + +} Camera_StatusTypeDef; + +#define RESOLUTION_R160x120 CAMERA_R160x120 /* QQVGA Resolution */ +#define RESOLUTION_R320x240 CAMERA_R320x240 /* QVGA Resolution */ +#define RESOLUTION_R480x272 CAMERA_R480x272 /* 480x272 Resolution */ +#define RESOLUTION_R640x480 CAMERA_R640x480 /* VGA Resolution */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_CAMERA_Exported_Constants STM32F7508_DISCOVERY_CAMERA Exported Constants + * @{ + */ +#define BSP_CAMERA_IRQHandler DCMI_IRQHandler +#define BSP_CAMERA_DMA_IRQHandler DMA2_Stream1_IRQHandler + +/** + * @} + */ + +/** @addtogroup STM32F7508_DISCOVERY_CAMERA_Exported_Functions + * @{ + */ +uint8_t BSP_CAMERA_Init(uint32_t Resolution); +uint8_t BSP_CAMERA_DeInit(void); +void BSP_CAMERA_ContinuousStart(uint8_t *buff); +void BSP_CAMERA_SnapshotStart(uint8_t *buff); +void BSP_CAMERA_Suspend(void); +void BSP_CAMERA_Resume(void); +uint8_t BSP_CAMERA_Stop(void); +void BSP_CAMERA_PwrUp(void); +void BSP_CAMERA_PwrDown(void); +void BSP_CAMERA_LineEventCallback(void); +void BSP_CAMERA_VsyncEventCallback(void); +void BSP_CAMERA_FrameEventCallback(void); +void BSP_CAMERA_ErrorCallback(void); + +/* Camera features functions prototype */ +void BSP_CAMERA_ContrastBrightnessConfig(uint32_t contrast_level, uint32_t brightness_level); +void BSP_CAMERA_BlackWhiteConfig(uint32_t Mode); +void BSP_CAMERA_ColorEffectConfig(uint32_t Effect); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_CAMERA_MspInit(DCMI_HandleTypeDef *hdcmi, void *Params); +void BSP_CAMERA_MspDeInit(DCMI_HandleTypeDef *hdcmi, void *Params); + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7508_DISCOVERY_CAMERA_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_eeprom.c b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_eeprom.c new file mode 100644 index 00000000..ed2bd4a0 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_eeprom.c @@ -0,0 +1,461 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_eeprom.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage an I2C M24LR64 + * EEPROM memory. + @verbatim + To be able to use this driver, the switch EE_M24LR64 must be defined + in your toolchain compiler preprocessor + + =================================================================== + Notes: + - The I2C EEPROM memory (M24LR64) is available on separate daughter + board ANT7-M24LR-A, which is not provided with the STM32F7508_DISCOVERY + board. + To use this driver you have to connect the ANT7-M24LR-A to CN3 + connector of STM32F7508_DISCOVERY board. + =================================================================== + + It implements a high level communication layer for read and write + from/to this memory. The needed STM32F7xx hardware resources (I2C and + GPIO) are defined in stm32f7508_discovery.h file, and the initialization is + performed in EEPROM_IO_Init() function declared in stm32f7508_discovery.c + file. + You can easily tailor this driver to any other development board, + by just adapting the defines for hardware resources and + EEPROM_IO_Init() function. + + @note In this driver, basic read and write functions (BSP_EEPROM_ReadBuffer() + and BSP_EEPROM_WritePage()) use DMA mode to perform the data + transfer to/from EEPROM memory. + + @note Regarding BSP_EEPROM_WritePage(), it is an optimized function to perform + small write (less than 1 page) BUT the number of bytes (combined to write start address) must not + cross the EEPROM page boundary. This function can only writes into + the boundaries of an EEPROM page. + This function doesn't check on boundaries condition (in this driver + the function BSP_EEPROM_WriteBuffer() which calls BSP_EEPROM_WritePage() is + responsible of checking on Page boundaries). + + + +-----------------------------------------------------------------+ + | Pin assignment for M24LR64 EEPROM | + +---------------------------------------+-----------+-------------+ + | STM32F7xx I2C Pins | EEPROM | Pin | + +---------------------------------------+-----------+-------------+ + | . | E0(GND) | 1 (0V) | + | . | AC0 | 2 | + | . | AC1 | 3 | + | . | VSS | 4 (0V) | + | SDA | SDA | 5 | + | SCL | SCL | 6 | + | . | E1(GND) | 7 (0V) | + | . | VDD | 8 (3.3V) | + +---------------------------------------+-----------+-------------+ + @endverbatim + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7508_discovery.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7508_discovery_eeprom.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY_EEPROM + * @brief This file includes the I2C EEPROM driver of STM32F7508-Discovery board. + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_EEPROM_Private_Types STM32F7508_DISCOVERY_EEPROM Private Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_EEPROM_Private_Defines STM32F7508_DISCOVERY_EEPROM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_EEPROM_Private_Macros STM32F7508_DISCOVERY_EEPROM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_EEPROM_Private_Variables STM32F7508_DISCOVERY_EEPROM Private Variables + * @{ + */ +__IO uint16_t EEPROMAddress = 0; +__IO uint16_t EEPROMDataRead; +__IO uint8_t EEPROMDataWrite; +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_EEPROM_Private_Function_Prototypes STM32F7508_DISCOVERY_EEPROM Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_EEPROM_Exported_Functions STM32F7508_DISCOVERY_EEPROM Exported Functions + * @{ + */ + +/** + * @brief Initializes peripherals used by the I2C EEPROM driver. + * + * @note There are 2 different versions of M24LR64 (A01 & A02). + * Then try to connect on 1st one (EEPROM_I2C_ADDRESS_A01) + * and if problem, check the 2nd one (EEPROM_I2C_ADDRESS_A02) + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) + */ +uint32_t BSP_EEPROM_Init(void) +{ + /* I2C Initialization */ + EEPROM_IO_Init(); + + /* Select the EEPROM address for A01 and check if OK */ + EEPROMAddress = EEPROM_I2C_ADDRESS_A01; + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + /* Select the EEPROM address for A02 and check if OK */ + EEPROMAddress = EEPROM_I2C_ADDRESS_A02; + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + return EEPROM_FAIL; + } + } + return EEPROM_OK; +} + +/** + * @brief DeInitializes the EEPROM. + * @retval EEPROM state + */ +uint8_t BSP_EEPROM_DeInit(void) +{ + /* I2C won't be disabled because common to other functionalities */ + return EEPROM_OK; +} + +/** + * @brief Reads a block of data from the EEPROM. + * @param pBuffer: pointer to the buffer that receives the data read from + * the EEPROM. + * @param ReadAddr: EEPROM's internal address to start reading from. + * @param NumByteToRead: pointer to the variable holding number of bytes to + * be read from the EEPROM. + * + * @note The variable pointed by NumByteToRead is reset to 0 when all the + * data are read from the EEPROM. Application should monitor this + * variable in order know when the transfer is complete. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead) +{ + uint32_t buffersize = *NumByteToRead; + + /* Set the pointer to the Number of data to be read. This pointer will be used + by the DMA Transfer Completer interrupt Handler in order to reset the + variable to 0. User should check on this variable in order to know if the + DMA transfer has been complete or not. */ + EEPROMDataRead = *NumByteToRead; + + if(EEPROM_IO_ReadData(EEPROMAddress, ReadAddr, pBuffer, buffersize) != HAL_OK) + { + BSP_EEPROM_TIMEOUT_UserCallback(); + return EEPROM_FAIL; + } + + /* If all operations OK, return EEPROM_OK (0) */ + return EEPROM_OK; +} + +/** + * @brief Writes more than one byte to the EEPROM with a single WRITE cycle. + * + * @note The number of bytes (combined to write start address) must not + * cross the EEPROM page boundary. This function can only write into + * the boundaries of an EEPROM page. + * This function doesn't check on boundaries condition (in this driver + * the function BSP_EEPROM_WriteBuffer() which calls BSP_EEPROM_WritePage() is + * responsible of checking on Page boundaries). + * + * @param pBuffer: pointer to the buffer containing the data to be written to + * the EEPROM. + * @param WriteAddr: EEPROM's internal address to write to. + * @param NumByteToWrite: pointer to the variable holding number of bytes to + * be written into the EEPROM. + * + * @note The variable pointed by NumByteToWrite is reset to 0 when all the + * data are written to the EEPROM. Application should monitor this + * variable in order know when the transfer is complete. + * + * @note This function just configure the communication and enable the DMA + * channel to transfer data. Meanwhile, the user application may perform + * other tasks in parallel. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite) +{ + uint32_t buffersize = *NumByteToWrite; + uint32_t status = EEPROM_OK; + + /* Set the pointer to the Number of data to be written. This pointer will be used + by the DMA Transfer Completer interrupt Handler in order to reset the + variable to 0. User should check on this variable in order to know if the + DMA transfer has been complete or not. */ + EEPROMDataWrite = *NumByteToWrite; + + if(EEPROM_IO_WriteData(EEPROMAddress, WriteAddr, pBuffer, buffersize) != HAL_OK) + { + BSP_EEPROM_TIMEOUT_UserCallback(); + status = EEPROM_FAIL; + } + + if(BSP_EEPROM_WaitEepromStandbyState() != EEPROM_OK) + { + return EEPROM_FAIL; + } + + /* If all operations OK, return EEPROM_OK (0) */ + return status; +} + +/** + * @brief Writes buffer of data to the I2C EEPROM. + * @param pBuffer: pointer to the buffer containing the data to be written + * to the EEPROM. + * @param WriteAddr: EEPROM's internal address to write to. + * @param NumByteToWrite: number of bytes to write to the EEPROM. + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WriteBuffer(uint8_t *pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite) +{ + uint16_t numofpage = 0, numofsingle = 0, count = 0; + uint16_t addr = 0; + uint8_t dataindex = 0; + uint32_t status = EEPROM_OK; + + addr = WriteAddr % EEPROM_PAGESIZE; + count = EEPROM_PAGESIZE - addr; + numofpage = NumByteToWrite / EEPROM_PAGESIZE; + numofsingle = NumByteToWrite % EEPROM_PAGESIZE; + + /* If WriteAddr is EEPROM_PAGESIZE aligned */ + if(addr == 0) + { + /* If NumByteToWrite < EEPROM_PAGESIZE */ + if(numofpage == 0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + /* Start writing data */ + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + /* If NumByteToWrite > EEPROM_PAGESIZE */ + else + { + while(numofpage--) + { + /* Store the number of data to be written */ + dataindex = EEPROM_PAGESIZE; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + + WriteAddr += EEPROM_PAGESIZE; + pBuffer += EEPROM_PAGESIZE; + } + + if(numofsingle!=0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + } + /* If WriteAddr is not EEPROM_PAGESIZE aligned */ + else + { + /* If NumByteToWrite < EEPROM_PAGESIZE */ + if(numofpage== 0) + { + /* If the number of data to be written is more than the remaining space + in the current page: */ + if(NumByteToWrite > count) + { + /* Store the number of data to be written */ + dataindex = count; + /* Write the data contained in same page */ + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + + /* Store the number of data to be written */ + dataindex = (NumByteToWrite - count); + /* Write the remaining data in the following page */ + status = BSP_EEPROM_WritePage((uint8_t*)(pBuffer + count), (WriteAddr + count), (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + else + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + /* If NumByteToWrite > EEPROM_PAGESIZE */ + else + { + NumByteToWrite -= count; + numofpage = NumByteToWrite / EEPROM_PAGESIZE; + numofsingle = NumByteToWrite % EEPROM_PAGESIZE; + + if(count != 0) + { + /* Store the number of data to be written */ + dataindex = count; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + WriteAddr += count; + pBuffer += count; + } + + while(numofpage--) + { + /* Store the number of data to be written */ + dataindex = EEPROM_PAGESIZE; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + WriteAddr += EEPROM_PAGESIZE; + pBuffer += EEPROM_PAGESIZE; + } + if(numofsingle != 0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + } + + /* If all operations OK, return EEPROM_OK (0) */ + return EEPROM_OK; +} + +/** + * @brief Wait for EEPROM Standby state. + * + * @note This function allows to wait and check that EEPROM has finished the + * last operation. It is mostly used after Write operation: after receiving + * the buffer to be written, the EEPROM may need additional time to actually + * perform the write operation. During this time, it doesn't answer to + * I2C packets addressed to it. Once the write operation is complete + * the EEPROM responds to its address. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WaitEepromStandbyState(void) +{ + /* Check if the maximum allowed number of trials has bee reached */ + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + /* If the maximum number of trials has been reached, exit the function */ + BSP_EEPROM_TIMEOUT_UserCallback(); + return EEPROM_TIMEOUT; + } + return EEPROM_OK; +} + +/** + * @brief Basic management of the timeout situation. + * @retval None + */ +__weak void BSP_EEPROM_TIMEOUT_UserCallback(void) +{ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_eeprom.h b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_eeprom.h new file mode 100644 index 00000000..d4293d2a --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_eeprom.h @@ -0,0 +1,122 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_eeprom.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for + * the stm32f7508_discovery_eeprom.c firmware driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7508_DISCOVERY_EEPROM_H +#define __STM32F7508_DISCOVERY_EEPROM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7508_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY_EEPROM + * @brief This file includes the I2C EEPROM driver of STM32F7508-Discovery board. + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_EEPROM_Exported_Types STM32F7508_DISCOVERY_EEPROM Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_EEPROM_Exported_Constants STM32F7508_DISCOVERY_EEPROM Exported Constants + * @{ + */ +/* EEPROM hardware address and page size */ +#define EEPROM_PAGESIZE ((uint8_t)4) +#define EEPROM_MAX_SIZE ((uint16_t)0x2000) /* 64Kbit */ + + +/* Maximum number of trials for EEPROM_WaitEepromStandbyState() function */ +#define EEPROM_MAX_TRIALS ((uint32_t)3000) + +#define EEPROM_OK ((uint32_t)0) +#define EEPROM_FAIL ((uint32_t)1) +#define EEPROM_TIMEOUT ((uint32_t)2) +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_EEPROM_Exported_Macros STM32F7508_DISCOVERY_EEPROM Exported Macros + * @{ + */ +/** + * @} + */ + +/** @addtogroup STM32F7508_DISCOVERY_EEPROM_Exported_Functions + * @{ + */ +uint32_t BSP_EEPROM_Init(void); +uint8_t BSP_EEPROM_DeInit(void); +uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead); +uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite); +uint32_t BSP_EEPROM_WriteBuffer(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite); +uint32_t BSP_EEPROM_WaitEepromStandbyState(void); + +/* USER Callbacks: This function is declared as __weak in EEPROM driver and + should be implemented into user application. + BSP_EEPROM_TIMEOUT_UserCallback() function is called whenever a timeout condition + occurs during communication (waiting on an event that doesn't occur, bus + errors, busy devices ...). */ +void BSP_EEPROM_TIMEOUT_UserCallback(void); + +/* Link function for I2C EEPROM peripheral */ +void EEPROM_IO_Init(void); +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7508_DISCOVERY_EEPROM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_lcd.c b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_lcd.c new file mode 100644 index 00000000..d2b3a1bd --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_lcd.c @@ -0,0 +1,1647 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_lcd.c + * @author MCD Application Team + * @brief This file includes the driver for Liquid Crystal Display (LCD) module + * mounted on STM32F7508-Discovery board. + @verbatim + 1. How To use this driver: + -------------------------- + - This driver is used to drive directly an LCD TFT using the LTDC controller. + - This driver uses timing and setting for RK043FN48H LCD. + + 2. Driver description: + --------------------- + + Initialization steps: + o Initialize the LCD using the BSP_LCD_Init() function. + o Apply the Layer configuration using the BSP_LCD_LayerDefaultInit() function. + o Select the LCD layer to be used using the BSP_LCD_SelectLayer() function. + o Enable the LCD display using the BSP_LCD_DisplayOn() function. + + + Options + o Configure and enable the color keying functionality using the + BSP_LCD_SetColorKeying() function. + o Modify in the fly the transparency and/or the frame buffer address + using the following functions: + - BSP_LCD_SetTransparency() + - BSP_LCD_SetLayerAddress() + + + Display on LCD + o Clear the hole LCD using BSP_LCD_Clear() function or only one specified string + line using the BSP_LCD_ClearStringLine() function. + o Display a character on the specified line and column using the BSP_LCD_DisplayChar() + function or a complete string line using the BSP_LCD_DisplayStringAtLine() function. + o Display a string line on the specified position (x,y in pixel) and align mode + using the BSP_LCD_DisplayStringAtLine() function. + o Draw and fill a basic shapes (dot, line, rectangle, circle, ellipse, .. bitmap) + on LCD using the available set of functions. + @endverbatim + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7508_discovery.c +- stm32f7508_discovery_sdram.c +- stm32f7xx_hal_ltdc.c +- stm32f7xx_hal_ltdc_ex.c +- stm32f7xx_hal_dma2d.c +- stm32f7xx_hal_rcc_ex.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- rk043fn48h.h +- fonts.h +- font24.c +- font20.c +- font16.c +- font12.c +- font8.c" +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7508_discovery_lcd.h" +#include "../../../Utilities/Fonts/fonts.h" +#include "../../../Utilities/Fonts/font24.c" +#include "../../../Utilities/Fonts/font20.c" +#include "../../../Utilities/Fonts/font16.c" +#include "../../../Utilities/Fonts/font12.c" +#include "../../../Utilities/Fonts/font8.c" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY_LCD + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_LCD_Private_TypesDefinitions STM32F7508_DISCOVERY_LCD Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_LCD_Private_Defines STM32F7508_DISCOVERY LCD Private Defines + * @{ + */ +#define POLY_X(Z) ((int32_t)((Points + Z)->X)) +#define POLY_Y(Z) ((int32_t)((Points + Z)->Y)) +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_LCD_Private_Macros STM32F7508_DISCOVERY_LCD Private Macros + * @{ + */ +#define ABS(X) ((X) > 0 ? (X) : -(X)) +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_LCD_Private_Variables STM32F7508_DISCOVERY_LCD Private Variables + * @{ + */ +LTDC_HandleTypeDef hLtdcHandler; +static DMA2D_HandleTypeDef hDma2dHandler; + +/* Default LCD configuration with LCD Layer 1 */ +static uint32_t ActiveLayer = 0; +static LCD_DrawPropTypeDef DrawProp[MAX_LAYER_NUMBER]; +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_LCD_Private_FunctionPrototypes STM32F7508_DISCOVERY_LCD Private Function Prototypes + * @{ + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c); +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3); +static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex); +static void LL_ConvertLineToARGB8888(void * pSrc, void *pDst, uint32_t xSize, uint32_t ColorMode); +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_LCD_Exported_Functions STM32F7508_DISCOVERY_LCD Exported Functions + * @{ + */ + +/** + * @brief Initializes the LCD. + * @retval LCD state + */ +uint8_t BSP_LCD_Init(void) +{ + /* Select the used LCD */ + + /* The RK043FN48H LCD 480x272 is selected */ + /* Timing Configuration */ + hLtdcHandler.Init.HorizontalSync = (RK043FN48H_HSYNC - 1); + hLtdcHandler.Init.VerticalSync = (RK043FN48H_VSYNC - 1); + hLtdcHandler.Init.AccumulatedHBP = (RK043FN48H_HSYNC + RK043FN48H_HBP - 1); + hLtdcHandler.Init.AccumulatedVBP = (RK043FN48H_VSYNC + RK043FN48H_VBP - 1); + hLtdcHandler.Init.AccumulatedActiveH = (RK043FN48H_HEIGHT + RK043FN48H_VSYNC + RK043FN48H_VBP - 1); + hLtdcHandler.Init.AccumulatedActiveW = (RK043FN48H_WIDTH + RK043FN48H_HSYNC + RK043FN48H_HBP - 1); + hLtdcHandler.Init.TotalHeigh = (RK043FN48H_HEIGHT + RK043FN48H_VSYNC + RK043FN48H_VBP + RK043FN48H_VFP - 1); + hLtdcHandler.Init.TotalWidth = (RK043FN48H_WIDTH + RK043FN48H_HSYNC + RK043FN48H_HBP + RK043FN48H_HFP - 1); + + /* LCD clock configuration */ + BSP_LCD_ClockConfig(&hLtdcHandler, NULL); + + /* Initialize the LCD pixel width and pixel height */ + hLtdcHandler.LayerCfg->ImageWidth = RK043FN48H_WIDTH; + hLtdcHandler.LayerCfg->ImageHeight = RK043FN48H_HEIGHT; + + /* Background value */ + hLtdcHandler.Init.Backcolor.Blue = 0; + hLtdcHandler.Init.Backcolor.Green = 0; + hLtdcHandler.Init.Backcolor.Red = 0; + + /* Polarity */ + hLtdcHandler.Init.HSPolarity = LTDC_HSPOLARITY_AL; + hLtdcHandler.Init.VSPolarity = LTDC_VSPOLARITY_AL; + hLtdcHandler.Init.DEPolarity = LTDC_DEPOLARITY_AL; + hLtdcHandler.Init.PCPolarity = LTDC_PCPOLARITY_IPC; + hLtdcHandler.Instance = LTDC; + + if(HAL_LTDC_GetState(&hLtdcHandler) == HAL_LTDC_STATE_RESET) + { + /* Initialize the LCD Msp: this __weak function can be rewritten by the application */ + BSP_LCD_MspInit(&hLtdcHandler, NULL); + } + HAL_LTDC_Init(&hLtdcHandler); + + /* Assert display enable LCD_DISP pin */ + HAL_GPIO_WritePin(LCD_DISP_GPIO_PORT, LCD_DISP_PIN, GPIO_PIN_SET); + + /* Assert backlight LCD_BL_CTRL pin */ + HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_PORT, LCD_BL_CTRL_PIN, GPIO_PIN_SET); + +#if !defined(DATA_IN_ExtSDRAM) + /* Initialize the SDRAM */ + BSP_SDRAM_Init(); +#endif + + /* Initialize the font */ + BSP_LCD_SetFont(&LCD_DEFAULT_FONT); + + return LCD_OK; +} + +/** + * @brief DeInitializes the LCD. + * @retval LCD state + */ +uint8_t BSP_LCD_DeInit(void) +{ + /* Initialize the hLtdcHandler Instance parameter */ + hLtdcHandler.Instance = LTDC; + + /* Disable LTDC block */ + __HAL_LTDC_DISABLE(&hLtdcHandler); + + /* DeInit the LTDC */ + HAL_LTDC_DeInit(&hLtdcHandler); + + /* DeInit the LTDC MSP : this __weak function can be rewritten by the application */ + BSP_LCD_MspDeInit(&hLtdcHandler, NULL); + + return LCD_OK; +} + +/** + * @brief Gets the LCD X size. + * @retval Used LCD X size + */ +uint32_t BSP_LCD_GetXSize(void) +{ + return hLtdcHandler.LayerCfg[ActiveLayer].ImageWidth; +} + +/** + * @brief Gets the LCD Y size. + * @retval Used LCD Y size + */ +uint32_t BSP_LCD_GetYSize(void) +{ + return hLtdcHandler.LayerCfg[ActiveLayer].ImageHeight; +} + +/** + * @brief Set the LCD X size. + * @param imageWidthPixels : image width in pixels unit + * @retval None + */ +void BSP_LCD_SetXSize(uint32_t imageWidthPixels) +{ + hLtdcHandler.LayerCfg[ActiveLayer].ImageWidth = imageWidthPixels; +} + +/** + * @brief Set the LCD Y size. + * @param imageHeightPixels : image height in lines unit + * @retval None + */ +void BSP_LCD_SetYSize(uint32_t imageHeightPixels) +{ + hLtdcHandler.LayerCfg[ActiveLayer].ImageHeight = imageHeightPixels; +} + +/** + * @brief Initializes the LCD layer in ARGB8888 format (32 bits per pixel). + * @param LayerIndex: Layer foreground or background + * @param FB_Address: Layer frame buffer + * @retval None + */ +void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) +{ + LCD_LayerCfgTypeDef layer_cfg; + + /* Layer Init */ + layer_cfg.WindowX0 = 0; + layer_cfg.WindowX1 = BSP_LCD_GetXSize(); + layer_cfg.WindowY0 = 0; + layer_cfg.WindowY1 = BSP_LCD_GetYSize(); + layer_cfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888; + layer_cfg.FBStartAdress = FB_Address; + layer_cfg.Alpha = 255; + layer_cfg.Alpha0 = 0; + layer_cfg.Backcolor.Blue = 0; + layer_cfg.Backcolor.Green = 0; + layer_cfg.Backcolor.Red = 0; + layer_cfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; + layer_cfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; + layer_cfg.ImageWidth = BSP_LCD_GetXSize(); + layer_cfg.ImageHeight = BSP_LCD_GetYSize(); + + HAL_LTDC_ConfigLayer(&hLtdcHandler, &layer_cfg, LayerIndex); + + DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE; + DrawProp[LayerIndex].pFont = &Font24; + DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK; +} + +/** + * @brief Initializes the LCD layer in RGB565 format (16 bits per pixel). + * @param LayerIndex: Layer foreground or background + * @param FB_Address: Layer frame buffer + * @retval None + */ +void BSP_LCD_LayerRgb565Init(uint16_t LayerIndex, uint32_t FB_Address) +{ + LCD_LayerCfgTypeDef layer_cfg; + + /* Layer Init */ + layer_cfg.WindowX0 = 0; + layer_cfg.WindowX1 = BSP_LCD_GetXSize(); + layer_cfg.WindowY0 = 0; + layer_cfg.WindowY1 = BSP_LCD_GetYSize(); + layer_cfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; + layer_cfg.FBStartAdress = FB_Address; + layer_cfg.Alpha = 255; + layer_cfg.Alpha0 = 0; + layer_cfg.Backcolor.Blue = 0; + layer_cfg.Backcolor.Green = 0; + layer_cfg.Backcolor.Red = 0; + layer_cfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; + layer_cfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; + layer_cfg.ImageWidth = BSP_LCD_GetXSize(); + layer_cfg.ImageHeight = BSP_LCD_GetYSize(); + + HAL_LTDC_ConfigLayer(&hLtdcHandler, &layer_cfg, LayerIndex); + + DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE; + DrawProp[LayerIndex].pFont = &Font24; + DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK; +} + +/** + * @brief Selects the LCD Layer. + * @param LayerIndex: Layer foreground or background + * @retval None + */ +void BSP_LCD_SelectLayer(uint32_t LayerIndex) +{ + ActiveLayer = LayerIndex; +} + +/** + * @brief Sets an LCD Layer visible + * @param LayerIndex: Visible Layer + * @param State: New state of the specified layer + * This parameter can be one of the following values: + * @arg ENABLE + * @arg DISABLE + * @retval None + */ +void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState State) +{ + if(State == ENABLE) + { + __HAL_LTDC_LAYER_ENABLE(&hLtdcHandler, LayerIndex); + } + else + { + __HAL_LTDC_LAYER_DISABLE(&hLtdcHandler, LayerIndex); + } + __HAL_LTDC_RELOAD_CONFIG(&hLtdcHandler); +} + +/** + * @brief Sets an LCD Layer visible without reloading. + * @param LayerIndex: Visible Layer + * @param State: New state of the specified layer + * This parameter can be one of the following values: + * @arg ENABLE + * @arg DISABLE + * @retval None + */ +void BSP_LCD_SetLayerVisible_NoReload(uint32_t LayerIndex, FunctionalState State) +{ + if(State == ENABLE) + { + __HAL_LTDC_LAYER_ENABLE(&hLtdcHandler, LayerIndex); + } + else + { + __HAL_LTDC_LAYER_DISABLE(&hLtdcHandler, LayerIndex); + } + /* Do not Sets the Reload */ +} + +/** + * @brief Configures the transparency. + * @param LayerIndex: Layer foreground or background. + * @param Transparency: Transparency + * This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF + * @retval None + */ +void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency) +{ + HAL_LTDC_SetAlpha(&hLtdcHandler, Transparency, LayerIndex); +} + +/** + * @brief Configures the transparency without reloading. + * @param LayerIndex: Layer foreground or background. + * @param Transparency: Transparency + * This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF + * @retval None + */ +void BSP_LCD_SetTransparency_NoReload(uint32_t LayerIndex, uint8_t Transparency) +{ + HAL_LTDC_SetAlpha_NoReload(&hLtdcHandler, Transparency, LayerIndex); +} + +/** + * @brief Sets an LCD layer frame buffer address. + * @param LayerIndex: Layer foreground or background + * @param Address: New LCD frame buffer value + * @retval None + */ +void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address) +{ + HAL_LTDC_SetAddress(&hLtdcHandler, Address, LayerIndex); +} + +/** + * @brief Sets an LCD layer frame buffer address without reloading. + * @param LayerIndex: Layer foreground or background + * @param Address: New LCD frame buffer value + * @retval None + */ +void BSP_LCD_SetLayerAddress_NoReload(uint32_t LayerIndex, uint32_t Address) +{ + HAL_LTDC_SetAddress_NoReload(&hLtdcHandler, Address, LayerIndex); +} + +/** + * @brief Sets display window. + * @param LayerIndex: Layer index + * @param Xpos: LCD X position + * @param Ypos: LCD Y position + * @param Width: LCD window width + * @param Height: LCD window height + * @retval None + */ +void BSP_LCD_SetLayerWindow(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Reconfigure the layer size */ + HAL_LTDC_SetWindowSize(&hLtdcHandler, Width, Height, LayerIndex); + + /* Reconfigure the layer position */ + HAL_LTDC_SetWindowPosition(&hLtdcHandler, Xpos, Ypos, LayerIndex); +} + +/** + * @brief Sets display window without reloading. + * @param LayerIndex: Layer index + * @param Xpos: LCD X position + * @param Ypos: LCD Y position + * @param Width: LCD window width + * @param Height: LCD window height + * @retval None + */ +void BSP_LCD_SetLayerWindow_NoReload(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Reconfigure the layer size */ + HAL_LTDC_SetWindowSize_NoReload(&hLtdcHandler, Width, Height, LayerIndex); + + /* Reconfigure the layer position */ + HAL_LTDC_SetWindowPosition_NoReload(&hLtdcHandler, Xpos, Ypos, LayerIndex); +} + +/** + * @brief Configures and sets the color keying. + * @param LayerIndex: Layer foreground or background + * @param RGBValue: Color reference + * @retval None + */ +void BSP_LCD_SetColorKeying(uint32_t LayerIndex, uint32_t RGBValue) +{ + /* Configure and Enable the color Keying for LCD Layer */ + HAL_LTDC_ConfigColorKeying(&hLtdcHandler, RGBValue, LayerIndex); + HAL_LTDC_EnableColorKeying(&hLtdcHandler, LayerIndex); +} + +/** + * @brief Configures and sets the color keying without reloading. + * @param LayerIndex: Layer foreground or background + * @param RGBValue: Color reference + * @retval None + */ +void BSP_LCD_SetColorKeying_NoReload(uint32_t LayerIndex, uint32_t RGBValue) +{ + /* Configure and Enable the color Keying for LCD Layer */ + HAL_LTDC_ConfigColorKeying_NoReload(&hLtdcHandler, RGBValue, LayerIndex); + HAL_LTDC_EnableColorKeying_NoReload(&hLtdcHandler, LayerIndex); +} + +/** + * @brief Disables the color keying. + * @param LayerIndex: Layer foreground or background + * @retval None + */ +void BSP_LCD_ResetColorKeying(uint32_t LayerIndex) +{ + /* Disable the color Keying for LCD Layer */ + HAL_LTDC_DisableColorKeying(&hLtdcHandler, LayerIndex); +} + +/** + * @brief Disables the color keying without reloading. + * @param LayerIndex: Layer foreground or background + * @retval None + */ +void BSP_LCD_ResetColorKeying_NoReload(uint32_t LayerIndex) +{ + /* Disable the color Keying for LCD Layer */ + HAL_LTDC_DisableColorKeying_NoReload(&hLtdcHandler, LayerIndex); +} + +/** + * @brief Disables the color keying without reloading. + * @param ReloadType: can be one of the following values + * - LCD_RELOAD_IMMEDIATE + * - LCD_RELOAD_VERTICAL_BLANKING + * @retval None + */ +void BSP_LCD_Reload(uint32_t ReloadType) +{ + HAL_LTDC_Reload (&hLtdcHandler, ReloadType); +} + +/** + * @brief Sets the LCD text color. + * @param Color: Text color code ARGB(8-8-8-8) + * @retval None + */ +void BSP_LCD_SetTextColor(uint32_t Color) +{ + DrawProp[ActiveLayer].TextColor = Color; +} + +/** + * @brief Gets the LCD text color. + * @retval Used text color. + */ +uint32_t BSP_LCD_GetTextColor(void) +{ + return DrawProp[ActiveLayer].TextColor; +} + +/** + * @brief Sets the LCD background color. + * @param Color: Layer background color code ARGB(8-8-8-8) + * @retval None + */ +void BSP_LCD_SetBackColor(uint32_t Color) +{ + DrawProp[ActiveLayer].BackColor = Color; +} + +/** + * @brief Gets the LCD background color. + * @retval Used background colour + */ +uint32_t BSP_LCD_GetBackColor(void) +{ + return DrawProp[ActiveLayer].BackColor; +} + +/** + * @brief Sets the LCD text font. + * @param fonts: Layer font to be used + * @retval None + */ +void BSP_LCD_SetFont(sFONT *fonts) +{ + DrawProp[ActiveLayer].pFont = fonts; +} + +/** + * @brief Gets the LCD text font. + * @retval Used layer font + */ +sFONT *BSP_LCD_GetFont(void) +{ + return DrawProp[ActiveLayer].pFont; +} + +/** + * @brief Reads an LCD pixel. + * @param Xpos: X position + * @param Ypos: Y position + * @retval RGB pixel color + */ +uint32_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos) +{ + uint32_t ret = 0; + + if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint32_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + else if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB888) + { + /* Read data value from SDRAM memory */ + ret = (*(__IO uint32_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))) & 0x00FFFFFF); + } + else if((hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \ + (hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \ + (hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_AL88)) + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint16_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + else + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint8_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + + return ret; +} + +/** + * @brief Clears the hole LCD. + * @param Color: Color of the background + * @retval None + */ +void BSP_LCD_Clear(uint32_t Color) +{ + /* Clear the LCD */ + LL_FillBuffer(ActiveLayer, (uint32_t *)(hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress), BSP_LCD_GetXSize(), BSP_LCD_GetYSize(), 0, Color); +} + +/** + * @brief Clears the selected line. + * @param Line: Line to be cleared + * @retval None + */ +void BSP_LCD_ClearStringLine(uint32_t Line) +{ + uint32_t color_backup = DrawProp[ActiveLayer].TextColor; + DrawProp[ActiveLayer].TextColor = DrawProp[ActiveLayer].BackColor; + + /* Draw rectangle with background color */ + BSP_LCD_FillRect(0, (Line * DrawProp[ActiveLayer].pFont->Height), BSP_LCD_GetXSize(), DrawProp[ActiveLayer].pFont->Height); + + DrawProp[ActiveLayer].TextColor = color_backup; + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Displays one character. + * @param Xpos: Start column address + * @param Ypos: Line where to display the character shape. + * @param Ascii: Character ascii code + * This parameter must be a number between Min_Data = 0x20 and Max_Data = 0x7E + * @retval None + */ +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii) +{ + DrawChar(Xpos, Ypos, &DrawProp[ActiveLayer].pFont->table[(Ascii-' ') *\ + DrawProp[ActiveLayer].pFont->Height * ((DrawProp[ActiveLayer].pFont->Width + 7) / 8)]); +} + +/** + * @brief Displays characters on the LCD. + * @param Xpos: X position (in pixel) + * @param Ypos: Y position (in pixel) + * @param Text: Pointer to string to display on LCD + * @param Mode: Display mode + * This parameter can be one of the following values: + * @arg CENTER_MODE + * @arg RIGHT_MODE + * @arg LEFT_MODE + * @retval None + */ +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode) +{ + uint16_t ref_column = 1, i = 0; + uint32_t size = 0, xsize = 0; + uint8_t *ptr = Text; + + /* Get the text size */ + while (*ptr++) size ++ ; + + /* Characters number per line */ + xsize = (BSP_LCD_GetXSize()/DrawProp[ActiveLayer].pFont->Width); + + switch (Mode) + { + case CENTER_MODE: + { + ref_column = Xpos + ((xsize - size)* DrawProp[ActiveLayer].pFont->Width) / 2; + break; + } + case LEFT_MODE: + { + ref_column = Xpos; + break; + } + case RIGHT_MODE: + { + ref_column = - Xpos + ((xsize - size)*DrawProp[ActiveLayer].pFont->Width); + break; + } + default: + { + ref_column = Xpos; + break; + } + } + + /* Check that the Start column is located in the screen */ + if ((ref_column < 1) || (ref_column >= 0x8000)) + { + ref_column = 1; + } + + /* Send the string character by character on LCD */ + while ((*Text != 0) & (((BSP_LCD_GetXSize() - (i*DrawProp[ActiveLayer].pFont->Width)) & 0xFFFF) >= DrawProp[ActiveLayer].pFont->Width)) + { + /* Display one character on LCD */ + BSP_LCD_DisplayChar(ref_column, Ypos, *Text); + /* Decrement the column position by 16 */ + ref_column += DrawProp[ActiveLayer].pFont->Width; + /* Point on the next character */ + Text++; + i++; + } +} + +/** + * @brief Displays a maximum of 60 characters on the LCD. + * @param Line: Line where to display the character shape + * @param ptr: Pointer to string to display on LCD + * @retval None + */ +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr) +{ + BSP_LCD_DisplayStringAt(0, LINE(Line), ptr, LEFT_MODE); +} + +/** + * @brief Draws an horizontal line. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + * @retval None + */ +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t Xaddress = 0; + + /* Get the line address */ + if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) + { /* RGB565 format */ + Xaddress = (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress) + 2*(BSP_LCD_GetXSize()*Ypos + Xpos); + } + else + { /* ARGB8888 format */ + Xaddress = (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + } + + /* Write line */ + LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, Length, 1, 0, DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws a vertical line. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + * @retval None + */ +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t Xaddress = 0; + + /* Get the line address */ + if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) + { /* RGB565 format */ + Xaddress = (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress) + 2*(BSP_LCD_GetXSize()*Ypos + Xpos); + } + else + { /* ARGB8888 format */ + Xaddress = (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + } + + /* Write line */ + LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, 1, Length, (BSP_LCD_GetXSize() - 1), DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws an uni-line (between two points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @retval None + */ +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, num_add = 0, num_pixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + num_add = deltay; + num_pixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + num_add = deltax; + num_pixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= num_pixels; curpixel++) + { + BSP_LCD_DrawPixel(x, y, DrawProp[ActiveLayer].TextColor); /* Draw the current pixel */ + num += num_add; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Draws a rectangle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + * @retval None + */ +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Draw horizontal lines */ + BSP_LCD_DrawHLine(Xpos, Ypos, Width); + BSP_LCD_DrawHLine(Xpos, (Ypos+ Height), Width); + + /* Draw vertical lines */ + BSP_LCD_DrawVLine(Xpos, Ypos, Height); + BSP_LCD_DrawVLine((Xpos + Width), Ypos, Height); +} + +/** + * @brief Draws a circle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + * @retval None + */ +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t decision; /* Decision Variable */ + uint32_t current_x; /* Current X Value */ + uint32_t current_y; /* Current Y Value */ + + decision = 3 - (Radius << 1); + current_x = 0; + current_y = Radius; + + while (current_x <= current_y) + { + BSP_LCD_DrawPixel((Xpos + current_x), (Ypos - current_y), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - current_x), (Ypos - current_y), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + current_y), (Ypos - current_x), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - current_y), (Ypos - current_x), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + current_x), (Ypos + current_y), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - current_x), (Ypos + current_y), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + current_y), (Ypos + current_x), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - current_y), (Ypos + current_x), DrawProp[ActiveLayer].TextColor); + + if (decision < 0) + { + decision += (current_x << 2) + 6; + } + else + { + decision += ((current_x - current_y) << 2) + 10; + current_y--; + } + current_x++; + } +} + +/** + * @brief Draws an poly-line (between many points). + * @param Points: Pointer to the points array + * @param PointCount: Number of points + * @retval None + */ +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t x = 0, y = 0; + + if(PointCount < 2) + { + return; + } + + BSP_LCD_DrawLine(Points->X, Points->Y, (Points+PointCount-1)->X, (Points+PointCount-1)->Y); + + while(--PointCount) + { + x = Points->X; + y = Points->Y; + Points++; + BSP_LCD_DrawLine(x, y, Points->X, Points->Y); + } +} + +/** + * @brief Draws an ellipse on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + * @retval None + */ +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float k = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + k = (float)(rad2/rad1); + + do { + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/k)), (Ypos+y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/k)), (Ypos+y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/k)), (Ypos-y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/k)), (Ypos-y), DrawProp[ActiveLayer].TextColor); + + e2 = err; + if (e2 <= x) { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Draws a pixel on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param RGB_Code: Pixel color in ARGB mode (8-8-8-8) + * @retval None + */ +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t RGB_Code) +{ + /* Write data value to all SDRAM memory */ + if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) + { /* RGB565 format */ + *(__IO uint16_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))) = (uint16_t)RGB_Code; + } + else + { /* ARGB8888 format */ + *(__IO uint32_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))) = RGB_Code; + } +} + +/** + * @brief Draws a bitmap picture loaded in the internal Flash in ARGB888 format (32 bits per pixel). + * @param Xpos: Bmp X position in the LCD + * @param Ypos: Bmp Y position in the LCD + * @param pbmp: Pointer to Bmp picture address in the internal Flash + * @retval None + */ +void BSP_LCD_DrawBitmap(uint32_t Xpos, uint32_t Ypos, uint8_t *pbmp) +{ + uint32_t index = 0, width = 0, height = 0, bit_pixel = 0; + uint32_t address; + uint32_t input_color_mode = 0; + + /* Get bitmap data address offset */ + index = pbmp[10] + (pbmp[11] << 8) + (pbmp[12] << 16) + (pbmp[13] << 24); + + /* Read bitmap width */ + width = pbmp[18] + (pbmp[19] << 8) + (pbmp[20] << 16) + (pbmp[21] << 24); + + /* Read bitmap height */ + height = pbmp[22] + (pbmp[23] << 8) + (pbmp[24] << 16) + (pbmp[25] << 24); + + /* Read bit/pixel */ + bit_pixel = pbmp[28] + (pbmp[29] << 8); + + /* Set the address */ + address = hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (((BSP_LCD_GetXSize()*Ypos) + Xpos)*(4)); + + /* Get the layer pixel format */ + if ((bit_pixel/8) == 4) + { + input_color_mode = CM_ARGB8888; + } + else if ((bit_pixel/8) == 2) + { + input_color_mode = CM_RGB565; + } + else + { + input_color_mode = CM_RGB888; + } + + /* Bypass the bitmap header */ + pbmp += (index + (width * (height - 1) * (bit_pixel/8))); + + /* Convert picture to ARGB8888 pixel format */ + for(index=0; index < height; index++) + { + /* Pixel format conversion */ + LL_ConvertLineToARGB8888((uint32_t *)pbmp, (uint32_t *)address, width, input_color_mode); + + /* Increment the source and destination buffers */ + address+= (BSP_LCD_GetXSize()*4); + pbmp -= width*(bit_pixel/8); + } +} + +/** + * @brief Draws a full rectangle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + * @retval None + */ +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + uint32_t x_address = 0; + + /* Set the text color */ + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + + /* Get the rectangle start address */ + if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) + { /* RGB565 format */ + x_address = (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress) + 2*(BSP_LCD_GetXSize()*Ypos + Xpos); + } + else + { /* ARGB8888 format */ + x_address = (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + } + /* Fill the rectangle */ + LL_FillBuffer(ActiveLayer, (uint32_t *)x_address, Width, Height, (BSP_LCD_GetXSize() - Width), DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws a full circle. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + * @retval None + */ +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t decision; /* Decision Variable */ + uint32_t current_x; /* Current X Value */ + uint32_t current_y; /* Current Y Value */ + + decision = 3 - (Radius << 1); + + current_x = 0; + current_y = Radius; + + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + + while (current_x <= current_y) + { + if(current_y > 0) + { + BSP_LCD_DrawHLine(Xpos - current_y, Ypos + current_x, 2*current_y); + BSP_LCD_DrawHLine(Xpos - current_y, Ypos - current_x, 2*current_y); + } + + if(current_x > 0) + { + BSP_LCD_DrawHLine(Xpos - current_x, Ypos - current_y, 2*current_x); + BSP_LCD_DrawHLine(Xpos - current_x, Ypos + current_y, 2*current_x); + } + if (decision < 0) + { + decision += (current_x << 2) + 6; + } + else + { + decision += ((current_x - current_y) << 2) + 10; + current_y--; + } + current_x++; + } + + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawCircle(Xpos, Ypos, Radius); +} + +/** + * @brief Draws a full poly-line (between many points). + * @param Points: Pointer to the points array + * @param PointCount: Number of points + * @retval None + */ +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t X = 0, Y = 0, X2 = 0, Y2 = 0, X_center = 0, Y_center = 0, X_first = 0, Y_first = 0, pixelX = 0, pixelY = 0, counter = 0; + uint16_t image_left = 0, image_right = 0, image_top = 0, image_bottom = 0; + + image_left = image_right = Points->X; + image_top= image_bottom = Points->Y; + + for(counter = 1; counter < PointCount; counter++) + { + pixelX = POLY_X(counter); + if(pixelX < image_left) + { + image_left = pixelX; + } + if(pixelX > image_right) + { + image_right = pixelX; + } + + pixelY = POLY_Y(counter); + if(pixelY < image_top) + { + image_top = pixelY; + } + if(pixelY > image_bottom) + { + image_bottom = pixelY; + } + } + + if(PointCount < 2) + { + return; + } + + X_center = (image_left + image_right)/2; + Y_center = (image_bottom + image_top)/2; + + X_first = Points->X; + Y_first = Points->Y; + + while(--PointCount) + { + X = Points->X; + Y = Points->Y; + Points++; + X2 = Points->X; + Y2 = Points->Y; + + FillTriangle(X, X2, X_center, Y, Y2, Y_center); + FillTriangle(X, X_center, X2, Y, Y_center, Y2); + FillTriangle(X_center, X2, X, Y_center, Y2, Y); + } + + FillTriangle(X_first, X2, X_center, Y_first, Y2, Y_center); + FillTriangle(X_first, X_center, X2, Y_first, Y_center, Y2); + FillTriangle(X_center, X2, X_first, Y_center, Y2, Y_first); +} + +/** + * @brief Draws a full ellipse. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + * @retval None + */ +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float k = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + k = (float)(rad2/rad1); + + do + { + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/k)), (Ypos+y), (2*(uint16_t)(x/k) + 1)); + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/k)), (Ypos-y), (2*(uint16_t)(x/k) + 1)); + + e2 = err; + if (e2 <= x) + { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Enables the display. + * @retval None + */ +void BSP_LCD_DisplayOn(void) +{ + /* Display On */ + __HAL_LTDC_ENABLE(&hLtdcHandler); + HAL_GPIO_WritePin(LCD_DISP_GPIO_PORT, LCD_DISP_PIN, GPIO_PIN_SET); /* Assert LCD_DISP pin */ + HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_PORT, LCD_BL_CTRL_PIN, GPIO_PIN_SET); /* Assert LCD_BL_CTRL pin */ +} + +/** + * @brief Disables the display. + * @retval None + */ +void BSP_LCD_DisplayOff(void) +{ + /* Display Off */ + __HAL_LTDC_DISABLE(&hLtdcHandler); + HAL_GPIO_WritePin(LCD_DISP_GPIO_PORT, LCD_DISP_PIN, GPIO_PIN_RESET); /* De-assert LCD_DISP pin */ + HAL_GPIO_WritePin(LCD_BL_CTRL_GPIO_PORT, LCD_BL_CTRL_PIN, GPIO_PIN_RESET);/* De-assert LCD_BL_CTRL pin */ +} + +/** + * @brief Initializes the LTDC MSP. + * @param hltdc: LTDC handle + * @param Params + * @retval None + */ +__weak void BSP_LCD_MspInit(LTDC_HandleTypeDef *hltdc, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable the LTDC and DMA2D clocks */ + __HAL_RCC_LTDC_CLK_ENABLE(); + __HAL_RCC_DMA2D_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + __HAL_RCC_GPIOJ_CLK_ENABLE(); + __HAL_RCC_GPIOK_CLK_ENABLE(); + LCD_DISP_GPIO_CLK_ENABLE(); + LCD_BL_CTRL_GPIO_CLK_ENABLE(); + + /*** LTDC Pins configuration ***/ + /* GPIOE configuration */ + gpio_init_structure.Pin = GPIO_PIN_4; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = GPIO_AF14_LTDC; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_12; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = GPIO_AF9_LTDC; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + /* GPIOI LTDC alternate configuration */ + gpio_init_structure.Pin = GPIO_PIN_9 | GPIO_PIN_10 | \ + GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = GPIO_AF14_LTDC; + HAL_GPIO_Init(GPIOI, &gpio_init_structure); + + /* GPIOJ configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \ + GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | \ + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | \ + GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = GPIO_AF14_LTDC; + HAL_GPIO_Init(GPIOJ, &gpio_init_structure); + + /* GPIOK configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | \ + GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = GPIO_AF14_LTDC; + HAL_GPIO_Init(GPIOK, &gpio_init_structure); + + /* LCD_DISP GPIO configuration */ + gpio_init_structure.Pin = LCD_DISP_PIN; /* LCD_DISP pin has to be manually controlled */ + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + HAL_GPIO_Init(LCD_DISP_GPIO_PORT, &gpio_init_structure); + + /* LCD_BL_CTRL GPIO configuration */ + gpio_init_structure.Pin = LCD_BL_CTRL_PIN; /* LCD_BL_CTRL pin has to be manually controlled */ + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + HAL_GPIO_Init(LCD_BL_CTRL_GPIO_PORT, &gpio_init_structure); +} + +/** + * @brief DeInitializes BSP_LCD MSP. + * @param hltdc: LTDC handle + * @param Params + * @retval None + */ +__weak void BSP_LCD_MspDeInit(LTDC_HandleTypeDef *hltdc, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Disable LTDC block */ + __HAL_LTDC_DISABLE(hltdc); + + /* LTDC Pins deactivation */ + + /* GPIOE deactivation */ + gpio_init_structure.Pin = GPIO_PIN_4; + HAL_GPIO_DeInit(GPIOE, gpio_init_structure.Pin); + + /* GPIOG deactivation */ + gpio_init_structure.Pin = GPIO_PIN_12; + HAL_GPIO_DeInit(GPIOG, gpio_init_structure.Pin); + + /* GPIOI deactivation */ + gpio_init_structure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_12 | \ + GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_DeInit(GPIOI, gpio_init_structure.Pin); + + /* GPIOJ deactivation */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \ + GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | \ + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | \ + GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_DeInit(GPIOJ, gpio_init_structure.Pin); + + /* GPIOK deactivation */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | \ + GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; + HAL_GPIO_DeInit(GPIOK, gpio_init_structure.Pin); + + /* Disable LTDC clock */ + __HAL_RCC_LTDC_CLK_DISABLE(); + + /* GPIO pins clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Clock Config. + * @param hltdc: LTDC handle + * @param Params + * @note This API is called by BSP_LCD_Init() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_LCD_ClockConfig(LTDC_HandleTypeDef *hltdc, void *Params) +{ + static RCC_PeriphCLKInitTypeDef periph_clk_init_struct; + + /* RK043FN48H LCD clock configuration */ + /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */ + /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 Mhz */ + /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/5 = 38.4 Mhz */ + /* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_4 = 38.4/4 = 9.6Mhz */ + periph_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; + periph_clk_init_struct.PLLSAI.PLLSAIN = 192; + periph_clk_init_struct.PLLSAI.PLLSAIR = RK043FN48H_FREQUENCY_DIVIDER; + periph_clk_init_struct.PLLSAIDivR = RCC_PLLSAIDIVR_4; + HAL_RCCEx_PeriphCLKConfig(&periph_clk_init_struct); +} + + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Draws a character on LCD. + * @param Xpos: Line where to display the character shape + * @param Ypos: Start column address + * @param c: Pointer to the character data + * @retval None + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c) +{ + uint32_t i = 0, j = 0; + uint16_t height, width; + uint8_t offset; + uint8_t *pchar; + uint32_t line; + + height = DrawProp[ActiveLayer].pFont->Height; + width = DrawProp[ActiveLayer].pFont->Width; + + offset = 8 *((width + 7)/8) - width ; + + for(i = 0; i < height; i++) + { + pchar = ((uint8_t *)c + (width + 7)/8 * i); + + switch(((width + 7)/8)) + { + + case 1: + line = pchar[0]; + break; + + case 2: + line = (pchar[0]<< 8) | pchar[1]; + break; + + case 3: + default: + line = (pchar[0]<< 16) | (pchar[1]<< 8) | pchar[2]; + break; + } + + for (j = 0; j < width; j++) + { + if(line & (1 << (width- j + offset- 1))) + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp[ActiveLayer].TextColor); + } + else + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp[ActiveLayer].BackColor); + } + } + Ypos++; + } +} + +/** + * @brief Fills a triangle (between 3 points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @param x3: Point 3 X position + * @param y3: Point 3 Y position + * @retval None + */ +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, num_add = 0, num_pixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + num_add = deltay; + num_pixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + num_add = deltax; + num_pixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= num_pixels; curpixel++) + { + BSP_LCD_DrawLine(x, y, x3, y3); + + num += num_add; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Fills a buffer. + * @param LayerIndex: Layer index + * @param pDst: Pointer to destination buffer + * @param xSize: Buffer width + * @param ySize: Buffer height + * @param OffLine: Offset + * @param ColorIndex: Color index + * @retval None + */ +static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex) +{ + /* Register to memory mode with ARGB8888 as color Mode */ + hDma2dHandler.Init.Mode = DMA2D_R2M; + if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) + { /* RGB565 format */ + hDma2dHandler.Init.ColorMode = DMA2D_RGB565; + } + else + { /* ARGB8888 format */ + hDma2dHandler.Init.ColorMode = DMA2D_ARGB8888; + } + hDma2dHandler.Init.OutputOffset = OffLine; + + hDma2dHandler.Instance = DMA2D; + + /* DMA2D Initialization */ + if(HAL_DMA2D_Init(&hDma2dHandler) == HAL_OK) + { + if(HAL_DMA2D_ConfigLayer(&hDma2dHandler, LayerIndex) == HAL_OK) + { + if (HAL_DMA2D_Start(&hDma2dHandler, ColorIndex, (uint32_t)pDst, xSize, ySize) == HAL_OK) + { + /* Polling For DMA transfer */ + HAL_DMA2D_PollForTransfer(&hDma2dHandler, 10); + } + } + } +} + +/** + * @brief Converts a line to an ARGB8888 pixel format. + * @param pSrc: Pointer to source buffer + * @param pDst: Output color + * @param xSize: Buffer width + * @param ColorMode: Input color mode + * @retval None + */ +static void LL_ConvertLineToARGB8888(void *pSrc, void *pDst, uint32_t xSize, uint32_t ColorMode) +{ + /* Configure the DMA2D Mode, Color Mode and output offset */ + hDma2dHandler.Init.Mode = DMA2D_M2M_PFC; + hDma2dHandler.Init.ColorMode = DMA2D_ARGB8888; + hDma2dHandler.Init.OutputOffset = 0; + + /* Foreground Configuration */ + hDma2dHandler.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; + hDma2dHandler.LayerCfg[1].InputAlpha = 0xFF; + hDma2dHandler.LayerCfg[1].InputColorMode = ColorMode; + hDma2dHandler.LayerCfg[1].InputOffset = 0; + + hDma2dHandler.Instance = DMA2D; + + /* DMA2D Initialization */ + if(HAL_DMA2D_Init(&hDma2dHandler) == HAL_OK) + { + if(HAL_DMA2D_ConfigLayer(&hDma2dHandler, 1) == HAL_OK) + { + if (HAL_DMA2D_Start(&hDma2dHandler, (uint32_t)pSrc, (uint32_t)pDst, xSize, 1) == HAL_OK) + { + /* Polling For DMA transfer */ + HAL_DMA2D_PollForTransfer(&hDma2dHandler, 10); + } + } + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_lcd.h b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_lcd.h new file mode 100644 index 00000000..ce0812f2 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_lcd.h @@ -0,0 +1,251 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_lcd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f7508_discovery_lcd.c driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7508_DISCOVERY_LCD_H +#define __STM32F7508_DISCOVERY_LCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include LCD component Driver */ +/* LCD RK043FN48H-CT672B 4,3" 480x272 pixels */ +#include "../Components/rk043fn48h/rk043fn48h.h" + +/* Include SDRAM Driver */ +#include "stm32f7508_discovery_sdram.h" + +#include "stm32f7508_discovery.h" +#include "../../../Utilities/Fonts/fonts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY_LCD + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_LCD_Exported_Types STM32F7508_DISCOVERY_LCD Exported Types + * @{ + */ +typedef struct +{ + uint32_t TextColor; + uint32_t BackColor; + sFONT *pFont; +}LCD_DrawPropTypeDef; + +typedef struct +{ + int16_t X; + int16_t Y; +}Point, * pPoint; + +/** + * @brief Line mode structures definition + */ +typedef enum +{ + CENTER_MODE = 0x01, /* Center mode */ + RIGHT_MODE = 0x02, /* Right mode */ + LEFT_MODE = 0x03 /* Left mode */ +}Text_AlignModeTypdef; + +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_LCD_Exported_Constants STM32F7508_DISCOVERY_LCD Exported Constants + * @{ + */ +#define MAX_LAYER_NUMBER ((uint32_t)2) + +#define LCD_LayerCfgTypeDef LTDC_LayerCfgTypeDef + +#define LTDC_ACTIVE_LAYER ((uint32_t)1) /* Layer 1 */ +/** + * @brief LCD status structure definition + */ +#define LCD_OK ((uint8_t)0x00) +#define LCD_ERROR ((uint8_t)0x01) +#define LCD_TIMEOUT ((uint8_t)0x02) + +/** + * @brief LCD FB_StartAddress + */ +#define LCD_FB_START_ADDRESS ((uint32_t)0xC0000000) + +/** + * @brief LCD color + */ +#define LCD_COLOR_BLUE ((uint32_t)0xFF0000FF) +#define LCD_COLOR_GREEN ((uint32_t)0xFF00FF00) +#define LCD_COLOR_RED ((uint32_t)0xFFFF0000) +#define LCD_COLOR_CYAN ((uint32_t)0xFF00FFFF) +#define LCD_COLOR_MAGENTA ((uint32_t)0xFFFF00FF) +#define LCD_COLOR_YELLOW ((uint32_t)0xFFFFFF00) +#define LCD_COLOR_LIGHTBLUE ((uint32_t)0xFF8080FF) +#define LCD_COLOR_LIGHTGREEN ((uint32_t)0xFF80FF80) +#define LCD_COLOR_LIGHTRED ((uint32_t)0xFFFF8080) +#define LCD_COLOR_LIGHTCYAN ((uint32_t)0xFF80FFFF) +#define LCD_COLOR_LIGHTMAGENTA ((uint32_t)0xFFFF80FF) +#define LCD_COLOR_LIGHTYELLOW ((uint32_t)0xFFFFFF80) +#define LCD_COLOR_DARKBLUE ((uint32_t)0xFF000080) +#define LCD_COLOR_DARKGREEN ((uint32_t)0xFF008000) +#define LCD_COLOR_DARKRED ((uint32_t)0xFF800000) +#define LCD_COLOR_DARKCYAN ((uint32_t)0xFF008080) +#define LCD_COLOR_DARKMAGENTA ((uint32_t)0xFF800080) +#define LCD_COLOR_DARKYELLOW ((uint32_t)0xFF808000) +#define LCD_COLOR_WHITE ((uint32_t)0xFFFFFFFF) +#define LCD_COLOR_LIGHTGRAY ((uint32_t)0xFFD3D3D3) +#define LCD_COLOR_GRAY ((uint32_t)0xFF808080) +#define LCD_COLOR_DARKGRAY ((uint32_t)0xFF404040) +#define LCD_COLOR_BLACK ((uint32_t)0xFF000000) +#define LCD_COLOR_BROWN ((uint32_t)0xFFA52A2A) +#define LCD_COLOR_ORANGE ((uint32_t)0xFFFFA500) +#define LCD_COLOR_TRANSPARENT ((uint32_t)0xFF000000) + +/** + * @brief LCD default font + */ +#define LCD_DEFAULT_FONT Font24 + +/** + * @brief LCD Reload Types + */ +#define LCD_RELOAD_IMMEDIATE ((uint32_t)LTDC_SRCR_IMR) +#define LCD_RELOAD_VERTICAL_BLANKING ((uint32_t)LTDC_SRCR_VBR) + + +/** + * @brief LCD special pins + */ +/* Display enable pin */ +#define LCD_DISP_PIN GPIO_PIN_12 +#define LCD_DISP_GPIO_PORT GPIOI +#define LCD_DISP_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define LCD_DISP_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() + +/* Backlight control pin */ +#define LCD_BL_CTRL_PIN GPIO_PIN_3 +#define LCD_BL_CTRL_GPIO_PORT GPIOK +#define LCD_BL_CTRL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOK_CLK_ENABLE() +#define LCD_BL_CTRL_GPIO_CLK_DISABLE() __HAL_RCC_GPIOK_CLK_DISABLE() + +/** + * @} + */ + +/** @addtogroup STM32F7508_DISCOVERY_LCD_Exported_Functions + * @{ + */ +uint8_t BSP_LCD_Init(void); +uint8_t BSP_LCD_DeInit(void); +uint32_t BSP_LCD_GetXSize(void); +uint32_t BSP_LCD_GetYSize(void); +void BSP_LCD_SetXSize(uint32_t imageWidthPixels); +void BSP_LCD_SetYSize(uint32_t imageHeightPixels); + +/* Functions using the LTDC controller */ +void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FrameBuffer); +void BSP_LCD_LayerRgb565Init(uint16_t LayerIndex, uint32_t FB_Address); +void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency); +void BSP_LCD_SetTransparency_NoReload(uint32_t LayerIndex, uint8_t Transparency); +void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address); +void BSP_LCD_SetLayerAddress_NoReload(uint32_t LayerIndex, uint32_t Address); +void BSP_LCD_SetColorKeying(uint32_t LayerIndex, uint32_t RGBValue); +void BSP_LCD_SetColorKeying_NoReload(uint32_t LayerIndex, uint32_t RGBValue); +void BSP_LCD_ResetColorKeying(uint32_t LayerIndex); +void BSP_LCD_ResetColorKeying_NoReload(uint32_t LayerIndex); +void BSP_LCD_SetLayerWindow(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_SetLayerWindow_NoReload(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_SelectLayer(uint32_t LayerIndex); +void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState State); +void BSP_LCD_SetLayerVisible_NoReload(uint32_t LayerIndex, FunctionalState State); +void BSP_LCD_Reload(uint32_t ReloadType); + +void BSP_LCD_SetTextColor(uint32_t Color); +uint32_t BSP_LCD_GetTextColor(void); +void BSP_LCD_SetBackColor(uint32_t Color); +uint32_t BSP_LCD_GetBackColor(void); +void BSP_LCD_SetFont(sFONT *fonts); +sFONT *BSP_LCD_GetFont(void); + +uint32_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos); +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t pixel); +void BSP_LCD_Clear(uint32_t Color); +void BSP_LCD_ClearStringLine(uint32_t Line); +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr); +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode); +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii); + +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius); +void BSP_LCD_DrawBitmap(uint32_t Xpos, uint32_t Ypos, uint8_t *pbmp); + +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius); + +void BSP_LCD_DisplayOff(void); +void BSP_LCD_DisplayOn(void); + +/* These functions can be modified in case the current settings + need to be changed for specific application needs */ +void BSP_LCD_MspInit(LTDC_HandleTypeDef *hltdc, void *Params); +void BSP_LCD_MspDeInit(LTDC_HandleTypeDef *hltdc, void *Params); +void BSP_LCD_ClockConfig(LTDC_HandleTypeDef *hltdc, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7508_DISCOVERY_LCD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_qspi.c b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_qspi.c new file mode 100644 index 00000000..a4505646 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_qspi.c @@ -0,0 +1,782 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_qspi.c + * @author MCD Application Team + * @brief This file includes a standard driver for the N25Q128A QSPI + * memory mounted on STM32F7508-Discovery board. + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + (#) This driver is used to drive the N25Q128A QSPI external + memory mounted on STM32F7508-Discovery board. + + (#) This driver need a specific component driver (N25Q128A) to be included with. + + (#) Initialization steps: + (++) Initialize the QPSI external memory using the BSP_QSPI_Init() function. This + function includes the MSP layer hardware resources initialization and the + QSPI interface with the external memory. + + (#) QSPI memory operations + (++) QSPI memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_QSPI_Read()/BSP_QSPI_Write(). + (++) The function BSP_QSPI_GetInfo() returns the configuration of the QSPI memory. + (see the QSPI memory data sheet) + (++) Perform erase block operation using the function BSP_QSPI_Erase_Block() and by + specifying the block address. You can perform an erase operation of the whole + chip by calling the function BSP_QSPI_Erase_Chip(). + (++) The function BSP_QSPI_GetStatus() returns the current status of the QSPI memory. + (see the QSPI memory data sheet) + @endverbatim + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_qspi.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- n25q128a.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7508_discovery_qspi.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_QSPI STM32F7508_DISCOVERY_QSPI + * @{ + */ + + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup STM32F7508_DISCOVERY_QSPI_Private_Variables STM32F7508_DISCOVERY QSPI Private Variables + * @{ + */ +QSPI_HandleTypeDef QSPIHandle; + +/** + * @} + */ + + + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup STM32F7508_DISCOVERY_QSPI_Private_Functions STM32F7508_DISCOVERY QSPI Private Functions + * @{ + */ +static uint8_t QSPI_ResetMemory (QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_DummyCyclesCfg (QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_WriteEnable (QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_AutoPollingMemReady (QSPI_HandleTypeDef *hqspi, uint32_t Timeout); + +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_QSPI_Exported_Functions STM32F7508_DISCOVERY QSPI Exported Functions + * @{ + */ + +/** + * @brief Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Init(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level initialization */ + BSP_QSPI_MspInit(&QSPIHandle, NULL); + + /* QSPI initialization */ + QSPIHandle.Init.ClockPrescaler = 1; /* QSPI freq = 216 MHz/(1+1) = 108 Mhz */ + QSPIHandle.Init.FifoThreshold = 4; + QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; + QSPIHandle.Init.FlashSize = POSITION_VAL(N25Q128A_FLASH_SIZE) - 1; + QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE; /* Min 50ns for nonRead */ + QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; + QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1; + QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE; + + if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* QSPI memory reset */ + if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Configuration of the dummy cycles on QSPI memory side */ + if (QSPI_DummyCyclesCfg(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + return QSPI_OK; +} + +/** + * @brief De-Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_DeInit(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level De-initialization */ + BSP_QSPI_MspDeInit(&QSPIHandle, NULL); + + return QSPI_OK; +} + +/** + * @brief Reads an amount of data from the QSPI memory. + * @param pData: Pointer to data to be read + * @param ReadAddr: Read start address + * @param Size: Size of data to read + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the read command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = QUAD_INOUT_FAST_READ_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.Address = ReadAddr; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = N25Q128A_DUMMY_CYCLES_READ_QUAD; + s_command.NbData = Size; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Set S# timing for Read command */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_3_CYCLE); + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Restore S# timing for nonRead commands */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_6_CYCLE); + + return QSPI_OK; +} + +/** + * @brief Writes an amount of data to the QSPI memory. + * @param pData: Pointer to data to be written + * @param WriteAddr: Write start address + * @param Size: Size of data to write + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + uint32_t end_addr, current_size, current_addr; + + /* Calculation of the size between the write address and the end of the page */ + current_size = N25Q128A_PAGE_SIZE - (WriteAddr % N25Q128A_PAGE_SIZE); + + /* Check if the size of the data is less than the remaining place in the page */ + if (current_size > Size) + { + current_size = Size; + } + + /* Initialize the adress variables */ + current_addr = WriteAddr; + end_addr = WriteAddr + Size; + + /* Initialize the program command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = EXT_QUAD_IN_FAST_PROG_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Perform the write page by page */ + do + { + s_command.Address = current_addr; + s_command.NbData = current_size; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of program */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update the address and size variables for next page programming */ + current_addr += current_size; + pData += current_size; + current_size = ((current_addr + N25Q128A_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : N25Q128A_PAGE_SIZE; + } while (current_addr < end_addr); + + return QSPI_OK; +} + +/** + * @brief Erases the specified block of the QSPI memory. + * @param BlockAddress: Block address to erase + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = SUBSECTOR_ERASE_CMD; + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.Address = BlockAddress; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, N25Q128A_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Erases the entire QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Chip(void) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = BULK_ERASE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, N25Q128A_BULK_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Reads current status of the QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetStatus(void) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg; + + /* Initialize the read flag status register command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_FLAG_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Check the value of the register */ + if ((reg & (N25Q128A_FSR_PRERR | N25Q128A_FSR_VPPERR | N25Q128A_FSR_PGERR | N25Q128A_FSR_ERERR)) != 0) + { + return QSPI_ERROR; + } + else if ((reg & (N25Q128A_FSR_PGSUS | N25Q128A_FSR_ERSUS)) != 0) + { + return QSPI_SUSPENDED; + } + else if ((reg & N25Q128A_FSR_READY) != 0) + { + return QSPI_OK; + } + else + { + return QSPI_BUSY; + } +} + +/** + * @brief Return the configuration of the QSPI memory. + * @param pInfo: pointer on the configuration structure + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetInfo(QSPI_Info* pInfo) +{ + /* Configure the structure with the memory configuration */ + pInfo->FlashSize = N25Q128A_FLASH_SIZE; + pInfo->EraseSectorSize = N25Q128A_SUBSECTOR_SIZE; + pInfo->EraseSectorsNumber = (N25Q128A_FLASH_SIZE/N25Q128A_SUBSECTOR_SIZE); + pInfo->ProgPageSize = N25Q128A_PAGE_SIZE; + pInfo->ProgPagesNumber = (N25Q128A_FLASH_SIZE/N25Q128A_PAGE_SIZE); + + return QSPI_OK; +} + +/** + * @brief Configure the QSPI in memory-mapped mode + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_EnableMemoryMappedMode(void) +{ + QSPI_CommandTypeDef s_command; + QSPI_MemoryMappedTypeDef s_mem_mapped_cfg; + + /* Configure the command for the read instruction */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = QUAD_INOUT_FAST_READ_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_24_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = N25Q128A_DUMMY_CYCLES_READ_QUAD; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the memory mapped mode */ + s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; + s_mem_mapped_cfg.TimeOutPeriod = 0; + + if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @} + */ + +/** @addtogroup STM32F7508_DISCOVERY_QSPI_Private_Functions + * @{ + */ + +/** + * @brief QSPI MSP Initialization + * This function configures the hardware resources used in this example: + * - Peripheral's clock enable + * - Peripheral's GPIO Configuration + * - NVIC configuration for QSPI interrupt + * @retval None + */ +__weak void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /*##-1- Enable peripherals and GPIO Clocks #################################*/ + /* Enable the QuadSPI memory interface clock */ + QSPI_CLK_ENABLE(); + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + /* Enable GPIO clocks */ + QSPI_CS_GPIO_CLK_ENABLE(); + QSPI_CLK_GPIO_CLK_ENABLE(); + QSPI_D0_GPIO_CLK_ENABLE(); + QSPI_D1_GPIO_CLK_ENABLE(); + QSPI_D2_GPIO_CLK_ENABLE(); + QSPI_D3_GPIO_CLK_ENABLE(); + + /*##-2- Configure peripheral GPIO ##########################################*/ + /* QSPI CS GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CS_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF10_QUADSPI; + HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &gpio_init_structure); + + /* QSPI CLK GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CLK_PIN; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &gpio_init_structure); + + /* QSPI D0 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D0_PIN; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_D0_GPIO_PORT, &gpio_init_structure); + + /* QSPI D1 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D1_PIN; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_D1_GPIO_PORT, &gpio_init_structure); + + /* QSPI D2 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D2_PIN; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_D2_GPIO_PORT, &gpio_init_structure); + + /* QSPI D3 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D3_PIN; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_D3_GPIO_PORT, &gpio_init_structure); + + /*##-3- Configure the NVIC for QSPI #########################################*/ + /* NVIC configuration for QSPI interrupt */ + HAL_NVIC_SetPriority(QUADSPI_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(QUADSPI_IRQn); +} + +/** + * @brief QSPI MSP De-Initialization + * This function frees the hardware resources used in this example: + * - Disable the Peripheral's clock + * - Revert GPIO and NVIC configuration to their default state + * @retval None + */ +__weak void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + /*##-1- Disable the NVIC for QSPI ###########################################*/ + HAL_NVIC_DisableIRQ(QUADSPI_IRQn); + + /*##-2- Disable peripherals and GPIO Clocks ################################*/ + /* De-Configure QSPI pins */ + HAL_GPIO_DeInit(QSPI_CS_GPIO_PORT, QSPI_CS_PIN); + HAL_GPIO_DeInit(QSPI_CLK_GPIO_PORT, QSPI_CLK_PIN); + HAL_GPIO_DeInit(QSPI_D0_GPIO_PORT, QSPI_D0_PIN); + HAL_GPIO_DeInit(QSPI_D1_GPIO_PORT, QSPI_D1_PIN); + HAL_GPIO_DeInit(QSPI_D2_GPIO_PORT, QSPI_D2_PIN); + HAL_GPIO_DeInit(QSPI_D3_GPIO_PORT, QSPI_D3_PIN); + + /*##-3- Reset peripherals ##################################################*/ + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + + /* Disable the QuadSPI memory interface clock */ + QSPI_CLK_DISABLE(); +} + +/** + * @brief This function reset the QSPI memory. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the reset enable command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = RESET_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Send the reset memory command */ + s_command.Instruction = RESET_MEMORY_CMD; + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait the memory is ready */ + if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function configure the dummy cycles on memory side. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg; + + /* Initialize the read volatile configuration register command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_VOL_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations */ + if (QSPI_WriteEnable(hqspi) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update volatile configuration register (with new dummy cycles) */ + s_command.Instruction = WRITE_VOL_CFG_REG_CMD; + MODIFY_REG(reg, N25Q128A_VCR_NB_DUMMY, (N25Q128A_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(N25Q128A_VCR_NB_DUMMY))); + + /* Configure the write volatile configuration register command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function send a Write Enable and wait it is effective. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Enable write operations */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = WRITE_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for write enabling */ + s_config.Match = N25Q128A_SR_WREN; + s_config.Mask = N25Q128A_SR_WREN; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_1_LINE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function read the SR of the memory and wait the EOP. + * @param hqspi: QSPI handle + * @param Timeout + * @retval None + */ +static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Configure automatic polling mode to wait for memory ready */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + s_config.Match = 0; + s_config.Mask = N25Q128A_SR_WIP; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, Timeout) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_qspi.h b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_qspi.h new file mode 100644 index 00000000..8073ed9f --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_qspi.h @@ -0,0 +1,154 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_qspi.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f7508_discovery_qspi.c driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7508_DISCOVERY_QSPI_H +#define __STM32F7508_DISCOVERY_QSPI_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" +#include "../Components/n25q128a/n25q128a.h" + +/** @addtogroup STM32F7508_DISCOVERY_QSPI + * @{ + */ + + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup STM32F7508_DISCOVERY_QSPI_Exported_Constants STM32F7508_DISCOVERY_QSPI Exported Constants + * @{ + */ +/* QSPI Error codes */ +#define QSPI_OK ((uint8_t)0x00) +#define QSPI_ERROR ((uint8_t)0x01) +#define QSPI_BUSY ((uint8_t)0x02) +#define QSPI_NOT_SUPPORTED ((uint8_t)0x04) +#define QSPI_SUSPENDED ((uint8_t)0x08) + + +/* Definition for QSPI clock resources */ +#define QSPI_CLK_ENABLE() __HAL_RCC_QSPI_CLK_ENABLE() +#define QSPI_CLK_DISABLE() __HAL_RCC_QSPI_CLK_DISABLE() +#define QSPI_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_CLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_D0_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() +#define QSPI_D1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() +#define QSPI_D2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() +#define QSPI_D3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() + +#define QSPI_FORCE_RESET() __HAL_RCC_QSPI_FORCE_RESET() +#define QSPI_RELEASE_RESET() __HAL_RCC_QSPI_RELEASE_RESET() + +/* Definition for QSPI Pins */ +#define QSPI_CS_PIN GPIO_PIN_6 +#define QSPI_CS_GPIO_PORT GPIOB +#define QSPI_CLK_PIN GPIO_PIN_2 +#define QSPI_CLK_GPIO_PORT GPIOB +#define QSPI_D0_PIN GPIO_PIN_11 +#define QSPI_D0_GPIO_PORT GPIOD +#define QSPI_D1_PIN GPIO_PIN_12 +#define QSPI_D1_GPIO_PORT GPIOD +#define QSPI_D2_PIN GPIO_PIN_2 +#define QSPI_D2_GPIO_PORT GPIOE +#define QSPI_D3_PIN GPIO_PIN_13 +#define QSPI_D3_GPIO_PORT GPIOD + +/* N25Q128A13EF840E Micron memory */ +/* Size of the flash */ +#define QSPI_FLASH_SIZE 23 /* Address bus width to access whole memory space */ +#define QSPI_PAGE_SIZE 256 + +/* This alias is added as the name of Memory mapped fucntion changed */ +#define BSP_QSPI_MemoryMappedMode BSP_QSPI_EnableMemoryMappedMode +/** + * @} + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup STM32F7508_DISCOVERY_QSPI_Exported_Types STM32F7508_DISCOVERY_QSPI Exported Types + * @{ + */ +/* QSPI Info */ +typedef struct { + uint32_t FlashSize; /*!< Size of the flash */ + uint32_t EraseSectorSize; /*!< Size of sectors for the erase operation */ + uint32_t EraseSectorsNumber; /*!< Number of sectors for the erase operation */ + uint32_t ProgPageSize; /*!< Size of pages for the program operation */ + uint32_t ProgPagesNumber; /*!< Number of pages for the program operation */ +} QSPI_Info; + +/** + * @} + */ + + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup STM32F7508_DISCOVERY_QSPI_Exported_Functions + * @{ + */ +uint8_t BSP_QSPI_Init (void); +uint8_t BSP_QSPI_DeInit (void); +uint8_t BSP_QSPI_Read (uint8_t* pData, uint32_t ReadAddr, uint32_t Size); +uint8_t BSP_QSPI_Write (uint8_t* pData, uint32_t WriteAddr, uint32_t Size); +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress); +uint8_t BSP_QSPI_Erase_Chip (void); +uint8_t BSP_QSPI_GetStatus (void); +uint8_t BSP_QSPI_GetInfo (QSPI_Info* pInfo); +uint8_t BSP_QSPI_EnableMemoryMappedMode(void); + +/* These functions can be modified in case the current settings + need to be changed for specific application needs */ +void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params); +void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7508_DISCOVERY_QSPI_H */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sd.c b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sd.c new file mode 100644 index 00000000..06fa040b --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sd.c @@ -0,0 +1,590 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_sd.c + * @author MCD Application Team + * @brief This file includes the uSD card driver mounted on STM32F7508-Discovery + * board. + @verbatim + 1. How To use this driver: + -------------------------- + - This driver is used to drive the micro SD external card mounted on STM32F7508-Discovery + board. + - This driver does not need a specific component driver for the micro SD device + to be included with. + + 2. Driver description: + --------------------- + + Initialization steps: + o Initialize the micro SD card using the BSP_SD_Init() function. This + function includes the MSP layer hardware resources initialization and the + SDIO interface configuration to interface with the external micro SD. It + also includes the micro SD initialization sequence. + o To check the SD card presence you can use the function BSP_SD_IsDetected() which + returns the detection status + o If SD presence detection interrupt mode is desired, you must configure the + SD detection interrupt mode by calling the function BSP_SD_ITConfig(). The interrupt + is generated as an external interrupt whenever the micro SD card is + plugged/unplugged in/from the board. + o The function BSP_SD_GetCardInfo() is used to get the micro SD card information + which is stored in the structure "HAL_SD_CardInfoTypedef". + + + Micro SD card operations + o The micro SD card can be accessed with read/write block(s) operations once + it is ready for access. The access can be performed whether using the polling + mode by calling the functions BSP_SD_ReadBlocks()/BSP_SD_WriteBlocks(), or by DMA + transfer using the functions BSP_SD_ReadBlocks_DMA()/BSP_SD_WriteBlocks_DMA() + o The DMA transfer complete is used with interrupt mode. Once the SD transfer + is complete, the SD interrupt is handled using the function BSP_SD_IRQHandler(), + the DMA Tx/Rx transfer complete are handled using the functions + BSP_SD_DMA_Tx_IRQHandler()/BSP_SD_DMA_Rx_IRQHandler(). The corresponding user callbacks + are implemented by the user at application level. + o The SD erase block(s) is performed using the function BSP_SD_Erase() with specifying + the number of blocks to erase. + o The SD runtime status is returned when calling the function BSP_SD_GetCardState(). + + @endverbatim + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7508_discovery.c +- stm32f7xx_hal_sd.c +- stm32f7xx_ll_sdmmc.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7508_discovery_sd.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_SD STM32F7508_DISCOVERY_SD + * @{ + */ + + +/** @defgroup STM32F7508_DISCOVERY_SD_Private_TypesDefinitions STM32F7508_DISCOVERY_SD Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_SD_Private_Defines STM32F7508_DISCOVERY_SD Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_SD_Private_Macros STM32F7508_DISCOVERY_SD Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_SD_Private_Variables STM32F7508_DISCOVERY_SD Private Variables + * @{ + */ +SD_HandleTypeDef uSdHandle; + +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_SD_Private_FunctionPrototypes STM32F7508_DISCOVERY_SD Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_SD_Exported_Functions STM32F7508_DISCOVERY_SD Exported Functions + * @{ + */ + +/** + * @brief Initializes the SD card device. + * @retval SD status + */ +uint8_t BSP_SD_Init(void) +{ + uint8_t sd_state = MSD_OK; + + /* uSD device interface configuration */ + uSdHandle.Instance = SDMMC1; + + uSdHandle.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + uSdHandle.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE; + uSdHandle.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; + uSdHandle.Init.BusWide = SDMMC_BUS_WIDE_1B; + uSdHandle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + uSdHandle.Init.ClockDiv = SDMMC_TRANSFER_CLK_DIV; + + /* Msp SD Detect pin initialization */ + BSP_SD_Detect_MspInit(&uSdHandle, NULL); + if(BSP_SD_IsDetected() != SD_PRESENT) /* Check if SD card is present */ + { + return MSD_ERROR_SD_NOT_PRESENT; + } + + /* Msp SD initialization */ + BSP_SD_MspInit(&uSdHandle, NULL); + + /* HAL SD initialization */ + if(HAL_SD_Init(&uSdHandle) != HAL_OK) + { + sd_state = MSD_ERROR; + } + + /* Configure SD Bus width */ + if(sd_state == MSD_OK) + { + /* Enable wide operation */ + if(HAL_SD_ConfigWideBusOperation(&uSdHandle, SDMMC_BUS_WIDE_4B) != HAL_OK) + { + sd_state = MSD_ERROR; + } + else + { + sd_state = MSD_OK; + } + } + + return sd_state; +} + +/** + * @brief DeInitializes the SD card device. + * @retval SD status + */ +uint8_t BSP_SD_DeInit(void) +{ + uint8_t sd_state = MSD_OK; + + uSdHandle.Instance = SDMMC1; + + /* HAL SD deinitialization */ + if(HAL_SD_DeInit(&uSdHandle) != HAL_OK) + { + sd_state = MSD_ERROR; + } + + /* Msp SD deinitialization */ + uSdHandle.Instance = SDMMC1; + BSP_SD_MspDeInit(&uSdHandle, NULL); + + return sd_state; +} + +/** + * @brief Configures Interrupt mode for SD detection pin. + * @retval Returns MSD_OK + */ +uint8_t BSP_SD_ITConfig(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Configure Interrupt mode for SD detection pin */ + gpio_init_structure.Pin = SD_DETECT_PIN; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Mode = GPIO_MODE_IT_RISING_FALLING; + HAL_GPIO_Init(SD_DETECT_GPIO_PORT, &gpio_init_structure); + + /* Enable and set SD detect EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(SD_DETECT_EXTI_IRQn), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(SD_DETECT_EXTI_IRQn)); + + return MSD_OK; +} + +/** + * @brief Detects if SD card is correctly plugged in the memory slot or not. + * @retval Returns if SD is detected or not + */ +uint8_t BSP_SD_IsDetected(void) +{ + __IO uint8_t status = SD_PRESENT; + + /* Check SD card detect pin */ + if (HAL_GPIO_ReadPin(SD_DETECT_GPIO_PORT, SD_DETECT_PIN) == GPIO_PIN_SET) + { + status = SD_NOT_PRESENT; + } + + return status; +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @param Timeout: Timeout for read operation + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + if(HAL_SD_ReadBlocks(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks, Timeout) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @param Timeout: Timeout for write operation + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + if(HAL_SD_WriteBlocks(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks, Timeout) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in DMA mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks) +{ + /* Read block(s) in DMA transfer mode */ + if(HAL_SD_ReadBlocks_DMA(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in DMA mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks) +{ + /* Write block(s) in DMA transfer mode */ + if(HAL_SD_WriteBlocks_DMA(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Erases the specified memory area of the given SD card. + * @param StartAddr: Start byte address + * @param EndAddr: End byte address + * @retval SD status + */ +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr) +{ + if(HAL_SD_Erase(&uSdHandle, StartAddr, EndAddr) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Initializes the SD MSP. + * @param hsd: SD handle + * @param Params + * @retval None + */ +__weak void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params) +{ + static DMA_HandleTypeDef dma_rx_handle; + static DMA_HandleTypeDef dma_tx_handle; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SDIO clock */ + __HAL_RCC_SDMMC1_CLK_ENABLE(); + + /* Enable DMA2 clocks */ + __DMAx_TxRx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF12_SDMMC1; + + /* GPIOC configuration */ + gpio_init_structure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; + HAL_GPIO_Init(GPIOC, &gpio_init_structure); + + /* GPIOD configuration */ + gpio_init_structure.Pin = GPIO_PIN_2; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* NVIC configuration for SDIO interrupts */ + HAL_NVIC_SetPriority(SDMMC1_IRQn, 0x0E, 0); + HAL_NVIC_EnableIRQ(SDMMC1_IRQn); + + /* Configure DMA Rx parameters */ + dma_rx_handle.Init.Channel = SD_DMAx_Rx_CHANNEL; + dma_rx_handle.Init.Direction = DMA_PERIPH_TO_MEMORY; + dma_rx_handle.Init.PeriphInc = DMA_PINC_DISABLE; + dma_rx_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_rx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_rx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_rx_handle.Init.Mode = DMA_PFCTRL; + dma_rx_handle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + dma_rx_handle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + dma_rx_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_rx_handle.Init.MemBurst = DMA_MBURST_INC4; + dma_rx_handle.Init.PeriphBurst = DMA_PBURST_INC4; + + dma_rx_handle.Instance = SD_DMAx_Rx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsd, hdmarx, dma_rx_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_rx_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_rx_handle); + + /* Configure DMA Tx parameters */ + dma_tx_handle.Init.Channel = SD_DMAx_Tx_CHANNEL; + dma_tx_handle.Init.Direction = DMA_MEMORY_TO_PERIPH; + dma_tx_handle.Init.PeriphInc = DMA_PINC_DISABLE; + dma_tx_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_tx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_tx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_tx_handle.Init.Mode = DMA_PFCTRL; + dma_tx_handle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + dma_tx_handle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + dma_tx_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_tx_handle.Init.MemBurst = DMA_MBURST_INC4; + dma_tx_handle.Init.PeriphBurst = DMA_PBURST_INC4; + + dma_tx_handle.Instance = SD_DMAx_Tx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsd, hdmatx, dma_tx_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_tx_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_tx_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD_DMAx_Rx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SD_DMAx_Rx_IRQn); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD_DMAx_Tx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SD_DMAx_Tx_IRQn); +} + +/** + * @brief Initializes the SD Detect pin MSP. + * @param hsd: SD handle + * @param Params + * @retval None + */ +__weak void BSP_SD_Detect_MspInit(SD_HandleTypeDef *hsd, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + SD_DETECT_GPIO_CLK_ENABLE(); + + /* GPIO configuration in input for uSD_Detect signal */ + gpio_init_structure.Pin = SD_DETECT_PIN; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(SD_DETECT_GPIO_PORT, &gpio_init_structure); +} + +/** + * @brief DeInitializes the SD MSP. + * @param hsd: SD handle + * @param Params + * @retval None + */ +__weak void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params) +{ + static DMA_HandleTypeDef dma_rx_handle; + static DMA_HandleTypeDef dma_tx_handle; + + /* Disable NVIC for DMA transfer complete interrupts */ + HAL_NVIC_DisableIRQ(SD_DMAx_Rx_IRQn); + HAL_NVIC_DisableIRQ(SD_DMAx_Tx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_rx_handle.Instance = SD_DMAx_Rx_STREAM; + HAL_DMA_DeInit(&dma_rx_handle); + + /* Deinitialize the stream for new transfer */ + dma_tx_handle.Instance = SD_DMAx_Tx_STREAM; + HAL_DMA_DeInit(&dma_tx_handle); + + /* Disable NVIC for SDIO interrupts */ + HAL_NVIC_DisableIRQ(SDMMC1_IRQn); + + /* DeInit GPIO pins can be done in the application + (by surcharging this __weak function) */ + + /* Disable SDMMC1 clock */ + __HAL_RCC_SDMMC1_CLK_DISABLE(); + + /* GPIO pins clock and DMA clocks can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Gets the current SD card data status. + * @retval Data transfer state. + * This value can be one of the following values: + * @arg SD_TRANSFER_OK: No data transfer is acting + * @arg SD_TRANSFER_BUSY: Data transfer is acting + */ +uint8_t BSP_SD_GetCardState(void) +{ + return((HAL_SD_GetCardState(&uSdHandle) == HAL_SD_CARD_TRANSFER ) ? SD_TRANSFER_OK : SD_TRANSFER_BUSY); +} + + +/** + * @brief Get SD information about specific SD card. + * @param CardInfo: Pointer to HAL_SD_CardInfoTypedef structure + * @retval None + */ +void BSP_SD_GetCardInfo(HAL_SD_CardInfoTypeDef *CardInfo) +{ + /* Get SD card Information */ + HAL_SD_GetCardInfo(&uSdHandle, CardInfo); +} + +/** + * @brief SD Abort callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_AbortCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_AbortCallback(); +} + +/** + * @brief Tx Transfer completed callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_WriteCpltCallback(); +} + +/** + * @brief Rx Transfer completed callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_ReadCpltCallback(); +} + +/** + * @brief BSP SD Abort callbacks + * @retval None + */ +__weak void BSP_SD_AbortCallback(void) +{ + +} + +/** + * @brief BSP Tx Transfer completed callbacks + * @retval None + */ +__weak void BSP_SD_WriteCpltCallback(void) +{ + +} + +/** + * @brief BSP Rx Transfer completed callbacks + * @retval None + */ +__weak void BSP_SD_ReadCpltCallback(void) +{ + +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sd.h b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sd.h new file mode 100644 index 00000000..9dc5ab3d --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sd.h @@ -0,0 +1,145 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_sd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f7508_discovery_sd.c driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7508_DISCOVERY_SD_H +#define __STM32F7508_DISCOVERY_SD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7508_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY_SD + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_SD_Exported_Types STM32F7508_DISCOVERY_SD Exported Types + * @{ + */ + +/** + * @brief SD Card information structure + */ +#define BSP_SD_CardInfo HAL_SD_CardInfoTypeDef +/** + * @} + */ + +/** + * @brief SD status structure definition + */ +#define MSD_OK ((uint8_t)0x00) +#define MSD_ERROR ((uint8_t)0x01) +#define MSD_ERROR_SD_NOT_PRESENT ((uint8_t)0x02) + +/** + * @brief SD transfer state definition + */ +#define SD_TRANSFER_OK ((uint8_t)0x00) +#define SD_TRANSFER_BUSY ((uint8_t)0x01) + +/** @defgroup STM32F7508_DISCOVERY_SD_Exported_Constants STM32F7508_DISCOVERY_SD Exported Constants + * @{ + */ +#define SD_PRESENT ((uint8_t)0x01) +#define SD_NOT_PRESENT ((uint8_t)0x00) + +#define SD_DATATIMEOUT ((uint32_t)100000000) + +/* DMA definitions for SD DMA transfer */ +#define __DMAx_TxRx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define SD_DMAx_Tx_CHANNEL DMA_CHANNEL_4 +#define SD_DMAx_Rx_CHANNEL DMA_CHANNEL_4 +#define SD_DMAx_Tx_STREAM DMA2_Stream6 +#define SD_DMAx_Rx_STREAM DMA2_Stream3 +#define SD_DMAx_Tx_IRQn DMA2_Stream6_IRQn +#define SD_DMAx_Rx_IRQn DMA2_Stream3_IRQn +#define BSP_SDMMC_IRQHandler SDMMC1_IRQHandler +#define BSP_SDMMC_DMA_Tx_IRQHandler DMA2_Stream6_IRQHandler +#define BSP_SDMMC_DMA_Rx_IRQHandler DMA2_Stream3_IRQHandler +#define SD_DetectIRQHandler() HAL_GPIO_EXTI_IRQHandler(SD_DETECT_PIN) +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_SD_Exported_Macro STM32F7508_DISCOVERY_SD Exported Macro + * @{ + */ +/** + * @} + */ + +/** @addtogroup STM32F7508_DISCOVERY_SD_Exported_Functions + * @{ + */ +uint8_t BSP_SD_Init(void); +uint8_t BSP_SD_DeInit(void); +uint8_t BSP_SD_ITConfig(void); +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks); +uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks); +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); +uint8_t BSP_SD_GetCardState(void); +void BSP_SD_GetCardInfo(HAL_SD_CardInfoTypeDef *CardInfo); +uint8_t BSP_SD_IsDetected(void); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_Detect_MspInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_AbortCallback(void); +void BSP_SD_WriteCpltCallback(void); +void BSP_SD_ReadCpltCallback(void); +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7508_DISCOVERY_SD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sdram.c b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sdram.c new file mode 100644 index 00000000..abd6b368 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sdram.c @@ -0,0 +1,481 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_sdram.c + * @author MCD Application Team + * @brief This file includes the SDRAM driver for the MT48LC4M32B2B5-7 memory + * device mounted on STM32F7508-Discovery board. + @verbatim + 1. How To use this driver: + -------------------------- + - This driver is used to drive the MT48LC4M32B2B5-7 SDRAM external memory mounted + on STM32F7508-Discovery board. + - This driver does not need a specific component driver for the SDRAM device + to be included with. + + 2. Driver description: + --------------------- + + Initialization steps: + o Initialize the SDRAM external memory using the BSP_SDRAM_Init() function. This + function includes the MSP layer hardware resources initialization and the + FMC controller configuration to interface with the external SDRAM memory. + o It contains the SDRAM initialization sequence to program the SDRAM external + device using the function BSP_SDRAM_Initialization_sequence(). Note that this + sequence is standard for all SDRAM devices, but can include some differences + from a device to another. If it is the case, the right sequence should be + implemented separately. + + + SDRAM read/write operations + o SDRAM external memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_SDRAM_ReadData()/BSP_SDRAM_WriteData(), or by DMA transfer using the functions + BSP_SDRAM_ReadData_DMA()/BSP_SDRAM_WriteData_DMA(). + o The AHB access is performed with 32-bit width transaction, the DMA transfer + configuration is fixed at single (no burst) word transfer (see the + SDRAM_MspInit() static function). + o User can implement his own functions for read/write access with his desired + configurations. + o If interrupt mode is used for DMA transfer, the function BSP_SDRAM_DMA_IRQHandler() + is called in IRQ handler file, to serve the generated interrupt once the DMA + transfer is complete. + o You can send a command to the SDRAM device in runtime using the function + BSP_SDRAM_Sendcmd(), and giving the desired command as parameter chosen between + the predefined commands of the "FMC_SDRAM_CommandTypeDef" structure. + + @endverbatim + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_sdram.c +- stm32f7xx_ll_fmc.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7508_discovery_sdram.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_SDRAM STM32F7508_DISCOVERY_SDRAM + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_SDRAM_Private_Types_Definitions STM32F7508_DISCOVERY_SDRAM Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_SDRAM_Private_Defines STM32F7508_DISCOVERY_SDRAM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_SDRAM_Private_Macros STM32F7508_DISCOVERY_SDRAM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_SDRAM_Private_Variables STM32F7508_DISCOVERY_SDRAM Private Variables + * @{ + */ +SDRAM_HandleTypeDef sdramHandle; +static FMC_SDRAM_TimingTypeDef Timing; +static FMC_SDRAM_CommandTypeDef Command; +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_SDRAM_Private_Function_Prototypes STM32F7508_DISCOVERY_SDRAM Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_SDRAM_Exported_Functions STM32F7508_DISCOVERY_SDRAM Exported Functions + * @{ + */ + +/** + * @brief Initializes the SDRAM device. + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_Init(void) +{ + static uint8_t sdramstatus = SDRAM_ERROR; + /* SDRAM device configuration */ + sdramHandle.Instance = FMC_SDRAM_DEVICE; + + /* Timing configuration for 100Mhz as SD clock frequency (System clock is up to 200Mhz) */ + Timing.LoadToActiveDelay = 2; + Timing.ExitSelfRefreshDelay = 7; + Timing.SelfRefreshTime = 4; + Timing.RowCycleDelay = 7; + Timing.WriteRecoveryTime = 2; + Timing.RPDelay = 2; + Timing.RCDDelay = 2; + + sdramHandle.Init.SDBank = FMC_SDRAM_BANK1; + sdramHandle.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8; + sdramHandle.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; + sdramHandle.Init.MemoryDataWidth = SDRAM_MEMORY_WIDTH; + sdramHandle.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; + sdramHandle.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2; + sdramHandle.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; + sdramHandle.Init.SDClockPeriod = SDCLOCK_PERIOD; + sdramHandle.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE; + sdramHandle.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; + + /* SDRAM controller initialization */ + + BSP_SDRAM_MspInit(&sdramHandle, NULL); /* __weak function can be rewritten by the application */ + + if(HAL_SDRAM_Init(&sdramHandle, &Timing) != HAL_OK) + { + sdramstatus = SDRAM_ERROR; + } + else + { + sdramstatus = SDRAM_OK; + } + + /* SDRAM initialization sequence */ + BSP_SDRAM_Initialization_sequence(REFRESH_COUNT); + + return sdramstatus; +} + +/** + * @brief DeInitializes the SDRAM device. + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_DeInit(void) +{ + static uint8_t sdramstatus = SDRAM_ERROR; + /* SDRAM device de-initialization */ + sdramHandle.Instance = FMC_SDRAM_DEVICE; + + if(HAL_SDRAM_DeInit(&sdramHandle) != HAL_OK) + { + sdramstatus = SDRAM_ERROR; + } + else + { + sdramstatus = SDRAM_OK; + } + + /* SDRAM controller de-initialization */ + BSP_SDRAM_MspDeInit(&sdramHandle, NULL); + + return sdramstatus; +} + +/** + * @brief Programs the SDRAM device. + * @param RefreshCount: SDRAM refresh counter value + * @retval None + */ +void BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount) +{ + __IO uint32_t tmpmrd = 0; + + /* Step 1: Configure a clock configuration enable command */ + Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 2: Insert 100 us minimum delay */ + /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */ + HAL_Delay(1); + + /* Step 3: Configure a PALL (precharge all) command */ + Command.CommandMode = FMC_SDRAM_CMD_PALL; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 4: Configure an Auto Refresh command */ + Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 8; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 5: Program the external memory mode register */ + tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |\ + SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |\ + SDRAM_MODEREG_CAS_LATENCY_2 |\ + SDRAM_MODEREG_OPERATING_MODE_STANDARD |\ + SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; + + Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = tmpmrd; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 6: Set the refresh rate counter */ + /* Set the device refresh rate */ + HAL_SDRAM_ProgramRefreshRate(&sdramHandle, RefreshCount); +} + +/** + * @brief Reads an amount of data from the SDRAM memory in polling mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_ReadData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Read_32b(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Reads an amount of data from the SDRAM memory in DMA mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_ReadData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Read_DMA(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Writes an amount of data to the SDRAM memory in polling mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_WriteData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Write_32b(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Writes an amount of data to the SDRAM memory in DMA mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_WriteData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Write_DMA(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Sends command to the SDRAM bank. + * @param SdramCmd: Pointer to SDRAM command structure + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_Sendcmd(FMC_SDRAM_CommandTypeDef *SdramCmd) +{ + if(HAL_SDRAM_SendCommand(&sdramHandle, SdramCmd, SDRAM_TIMEOUT) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Initializes SDRAM MSP. + * @param hsdram: SDRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable FMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + + /* Enable chosen DMAx clock */ + __DMAx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = GPIO_AF12_FMC; + + /* GPIOC configuration */ + gpio_init_structure.Pin = GPIO_PIN_3; + HAL_GPIO_Init(GPIOC, &gpio_init_structure); + + /* GPIOD configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8 | GPIO_PIN_9 | + GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOE configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7| GPIO_PIN_8 | GPIO_PIN_9 |\ + GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\ + GPIO_PIN_15; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOF configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\ + GPIO_PIN_15; + HAL_GPIO_Init(GPIOF, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4| GPIO_PIN_5 | GPIO_PIN_8 |\ + GPIO_PIN_15; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + /* GPIOH configuration */ + gpio_init_structure.Pin = GPIO_PIN_3 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOH, &gpio_init_structure); + + /* Configure common DMA parameters */ + dma_handle.Init.Channel = SDRAM_DMAx_CHANNEL; + dma_handle.Init.Direction = DMA_MEMORY_TO_MEMORY; + dma_handle.Init.PeriphInc = DMA_PINC_ENABLE; + dma_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_handle.Init.Mode = DMA_NORMAL; + dma_handle.Init.Priority = DMA_PRIORITY_HIGH; + dma_handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + dma_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_handle.Init.MemBurst = DMA_MBURST_SINGLE; + dma_handle.Init.PeriphBurst = DMA_PBURST_SINGLE; + + dma_handle.Instance = SDRAM_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsdram, hdma, dma_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SDRAM_DMAx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SDRAM_DMAx_IRQn); +} + +/** + * @brief DeInitializes SDRAM MSP. + * @param hsdram: SDRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SDRAM_MspDeInit(SDRAM_HandleTypeDef *hsdram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + + /* Disable NVIC configuration for DMA interrupt */ + HAL_NVIC_DisableIRQ(SDRAM_DMAx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_handle.Instance = SDRAM_DMAx_STREAM; + HAL_DMA_DeInit(&dma_handle); + + /* GPIO pins clock, FMC clock and DMA clock can be shut down in the applications + by surcharging this __weak function */ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sdram.h b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sdram.h new file mode 100644 index 00000000..b2afb812 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_sdram.h @@ -0,0 +1,146 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_sdram.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f7508_discovery_sdram.c driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7508_DISCOVERY_SDRAM_H +#define __STM32F7508_DISCOVERY_SDRAM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY_SDRAM + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_SDRAM_Exported_Types STM32F7508_DISCOVERY_SDRAM Exported Types + * @{ + */ + +/** + * @brief SDRAM status structure definition + */ +#define SDRAM_OK ((uint8_t)0x00) +#define SDRAM_ERROR ((uint8_t)0x01) + +/** @defgroup STM32F7508_DISCOVERY_SDRAM_Exported_Constants STM32F7508_DISCOVERY_SDRAM Exported Constants + * @{ + */ +#define SDRAM_DEVICE_ADDR ((uint32_t)0xC0000000) +#define SDRAM_DEVICE_SIZE ((uint32_t)0x800000) /* SDRAM device size in MBytes */ + +/* #define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_8 */ +#define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_16 + +#define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_2 +/* #define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_3 */ + +#define REFRESH_COUNT ((uint32_t)0x0603) /* SDRAM refresh counter (100Mhz SD clock) */ + +#define SDRAM_TIMEOUT ((uint32_t)0xFFFF) + +/* DMA definitions for SDRAM DMA transfer */ +#define __DMAx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define __DMAx_CLK_DISABLE __HAL_RCC_DMA2_CLK_DISABLE +#define SDRAM_DMAx_CHANNEL DMA_CHANNEL_0 +#define SDRAM_DMAx_STREAM DMA2_Stream0 +#define SDRAM_DMAx_IRQn DMA2_Stream0_IRQn +#define BSP_SDRAM_DMA_IRQHandler DMA2_Stream0_IRQHandler +/** + * @} + */ + +/** + * @brief FMC SDRAM Mode definition register defines + */ +#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) +#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) +#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) +#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) +#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) +#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) +#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_SDRAM_Exported_Macro STM32F7508_DISCOVERY_SDRAM Exported Macro + * @{ + */ +/** + * @} + */ + +/** @addtogroup STM32F7508_DISCOVERY_SDRAM_Exported_Functions + * @{ + */ +uint8_t BSP_SDRAM_Init(void); +uint8_t BSP_SDRAM_DeInit(void); +void BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount); +uint8_t BSP_SDRAM_ReadData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_ReadData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_WriteData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_WriteData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_Sendcmd(FMC_SDRAM_CommandTypeDef *SdramCmd); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram, void *Params); +void BSP_SDRAM_MspDeInit(SDRAM_HandleTypeDef *hsdram, void *Params); + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7508_DISCOVERY_SDRAM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_ts.c b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_ts.c new file mode 100644 index 00000000..127e5411 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_ts.c @@ -0,0 +1,434 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_ts.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the Touch + * Screen on STM32F7508-Discovery board. + @verbatim + 1. How To use this driver: + -------------------------- + - This driver is used to drive the touch screen module of the STM32F7508-Discovery + board on the RK043FN48H-CT672B 480x272 LCD screen with capacitive touch screen. + - The FT5336 component driver must be included in project files according to + the touch screen driver present on this board. + + 2. Driver description: + --------------------- + + Initialization steps: + o Initialize the TS module using the BSP_TS_Init() function. This + function includes the MSP layer hardware resources initialization and the + communication layer configuration to start the TS use. The LCD size properties + (x and y) are passed as parameters. + o If TS interrupt mode is desired, you must configure the TS interrupt mode + by calling the function BSP_TS_ITConfig(). The TS interrupt mode is generated + as an external interrupt whenever a touch is detected. + The interrupt mode internally uses the IO functionalities driver driven by + the IO expander, to configure the IT line. + + + Touch screen use + o The touch screen state is captured whenever the function BSP_TS_GetState() is + used. This function returns information about the last LCD touch occurred + in the TS_StateTypeDef structure. + o If TS interrupt mode is used, the function BSP_TS_ITGetStatus() is needed to get + the interrupt status. To clear the IT pending bits, you should call the + function BSP_TS_ITClear(). + o The IT is handled using the corresponding external interrupt IRQ handler, + the user IT callback treatment is implemented on the same external interrupt + callback. + @endverbatim + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7508_discovery_lcd.c +- ft5336.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7508_discovery_ts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_TS STM32F7508_DISCOVERY_TS + * @{ + */ + +/** @defgroup STM32F7508_DISCOVERY_TS_Private_Types_Definitions STM32F7508_DISCOVERY_TS Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_TS_Private_Defines STM32F7508_DISCOVERY_TS Types Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_TS_Private_Macros STM32F7508_DISCOVERY_TS Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_TS_Imported_Variables STM32F7508_DISCOVERY_TS Imported Variables + * @{ + */ + /** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_TS_Private_Variables STM32F7508_DISCOVERY_TS Private Variables + * @{ + */ +static TS_DrvTypeDef *tsDriver; +static uint16_t tsXBoundary, tsYBoundary; +static uint8_t tsOrientation; +static uint8_t I2cAddress; +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_TS_Private_Function_Prototypes STM32F7508_DISCOVERY_TS Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_TS_Exported_Functions STM32F7508_DISCOVERY_TS Exported Functions + * @{ + */ + +/** + * @brief Initializes and configures the touch screen functionalities and + * configures all necessary hardware resources (GPIOs, I2C, clocks..). + * @param ts_SizeX: Maximum X size of the TS area on LCD + * @param ts_SizeY: Maximum Y size of the TS area on LCD + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY) +{ + uint8_t status = TS_OK; + tsXBoundary = ts_SizeX; + tsYBoundary = ts_SizeY; + + /* Read ID and verify if the touch screen driver is ready */ + ft5336_ts_drv.Init(TS_I2C_ADDRESS); + if(ft5336_ts_drv.ReadID(TS_I2C_ADDRESS) == FT5336_ID_VALUE) + { + /* Initialize the TS driver structure */ + tsDriver = &ft5336_ts_drv; + I2cAddress = TS_I2C_ADDRESS; + tsOrientation = TS_SWAP_XY; + + /* Initialize the TS driver */ + tsDriver->Start(I2cAddress); + } + else + { + status = TS_DEVICE_NOT_FOUND; + } + + return status; +} + +/** + * @brief DeInitializes the TouchScreen. + * @retval TS state + */ +uint8_t BSP_TS_DeInit(void) +{ + /* Actually ts_driver does not provide a DeInit function */ + return TS_OK; +} + +/** + * @brief Configures and enables the touch screen interrupts. + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_ITConfig(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Configure Interrupt mode for SD detection pin */ + gpio_init_structure.Pin = TS_INT_PIN; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Mode = GPIO_MODE_IT_RISING; + HAL_GPIO_Init(TS_INT_GPIO_PORT, &gpio_init_structure); + + /* Enable and set Touch screen EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(TS_INT_EXTI_IRQn), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(TS_INT_EXTI_IRQn)); + + /* Enable the TS ITs */ + tsDriver->EnableIT(I2cAddress); + + return TS_OK; +} + +/** + * @brief Gets the touch screen interrupt status. + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_ITGetStatus(void) +{ + /* Return the TS IT status */ + return (tsDriver->GetITStatus(I2cAddress)); +} + +/** + * @brief Returns status and positions of the touch screen. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State) +{ + static uint32_t _x[TS_MAX_NB_TOUCH] = {0, 0}; + static uint32_t _y[TS_MAX_NB_TOUCH] = {0, 0}; + uint8_t ts_status = TS_OK; + uint16_t x[TS_MAX_NB_TOUCH]; + uint16_t y[TS_MAX_NB_TOUCH]; + uint16_t brute_x[TS_MAX_NB_TOUCH]; + uint16_t brute_y[TS_MAX_NB_TOUCH]; + uint16_t x_diff; + uint16_t y_diff; + uint32_t index; +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + uint32_t weight = 0; + uint32_t area = 0; + uint32_t event = 0; +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + /* Check and update the number of touches active detected */ + TS_State->touchDetected = tsDriver->DetectTouch(I2cAddress); + + if(TS_State->touchDetected) + { + for(index=0; index < TS_State->touchDetected; index++) + { + /* Get each touch coordinates */ + tsDriver->GetXY(I2cAddress, &(brute_x[index]), &(brute_y[index])); + + if(tsOrientation == TS_SWAP_NONE) + { + x[index] = brute_x[index]; + y[index] = brute_y[index]; + } + + if(tsOrientation & TS_SWAP_X) + { + x[index] = 4096 - brute_x[index]; + } + + if(tsOrientation & TS_SWAP_Y) + { + y[index] = 4096 - brute_y[index]; + } + + if(tsOrientation & TS_SWAP_XY) + { + y[index] = brute_x[index]; + x[index] = brute_y[index]; + } + + x_diff = x[index] > _x[index]? (x[index] - _x[index]): (_x[index] - x[index]); + y_diff = y[index] > _y[index]? (y[index] - _y[index]): (_y[index] - y[index]); + + if ((x_diff + y_diff) > 5) + { + _x[index] = x[index]; + _y[index] = y[index]; + } + + if(I2cAddress == FT5336_I2C_SLAVE_ADDRESS) + { + TS_State->touchX[index] = x[index]; + TS_State->touchY[index] = y[index]; + } + else + { + /* 2^12 = 4096 : indexes are expressed on a dynamic of 4096 */ + TS_State->touchX[index] = (tsXBoundary * _x[index]) >> 12; + TS_State->touchY[index] = (tsYBoundary * _y[index]) >> 12; + } + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + + /* Get touch info related to the current touch */ + ft5336_TS_GetTouchInfo(I2cAddress, index, &weight, &area, &event); + + /* Update TS_State structure */ + TS_State->touchWeight[index] = weight; + TS_State->touchArea[index] = area; + + /* Remap touch event */ + switch(event) + { + case FT5336_TOUCH_EVT_FLAG_PRESS_DOWN : + TS_State->touchEventId[index] = TOUCH_EVENT_PRESS_DOWN; + break; + case FT5336_TOUCH_EVT_FLAG_LIFT_UP : + TS_State->touchEventId[index] = TOUCH_EVENT_LIFT_UP; + break; + case FT5336_TOUCH_EVT_FLAG_CONTACT : + TS_State->touchEventId[index] = TOUCH_EVENT_CONTACT; + break; + case FT5336_TOUCH_EVT_FLAG_NO_EVENT : + TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT; + break; + default : + ts_status = TS_ERROR; + break; + } /* of switch(event) */ + +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + } /* of for(index=0; index < TS_State->touchDetected; index++) */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + /* Get gesture Id */ + ts_status = BSP_TS_Get_GestureId(TS_State); +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + } /* end of if(TS_State->touchDetected != 0) */ + + return (ts_status); +} + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +/** + * @brief Update gesture Id following a touch detected. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State) +{ + uint32_t gestureId = 0; + uint8_t ts_status = TS_OK; + + /* Get gesture Id */ + ft5336_TS_GetGestureID(I2cAddress, &gestureId); + + /* Remap gesture Id to a TS_GestureIdTypeDef value */ + switch(gestureId) + { + case FT5336_GEST_ID_NO_GESTURE : + TS_State->gestureId = GEST_ID_NO_GESTURE; + break; + case FT5336_GEST_ID_MOVE_UP : + TS_State->gestureId = GEST_ID_MOVE_UP; + break; + case FT5336_GEST_ID_MOVE_RIGHT : + TS_State->gestureId = GEST_ID_MOVE_RIGHT; + break; + case FT5336_GEST_ID_MOVE_DOWN : + TS_State->gestureId = GEST_ID_MOVE_DOWN; + break; + case FT5336_GEST_ID_MOVE_LEFT : + TS_State->gestureId = GEST_ID_MOVE_LEFT; + break; + case FT5336_GEST_ID_ZOOM_IN : + TS_State->gestureId = GEST_ID_ZOOM_IN; + break; + case FT5336_GEST_ID_ZOOM_OUT : + TS_State->gestureId = GEST_ID_ZOOM_OUT; + break; + default : + ts_status = TS_ERROR; + break; + } /* of switch(gestureId) */ + + return(ts_status); +} +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +/** + * @brief Clears all touch screen interrupts. + */ +void BSP_TS_ITClear(void) +{ + /* Clear TS IT pending bits */ + tsDriver->ClearIT(I2cAddress); +} + + +/** @defgroup STM32756G_DISCOVERY_TS_Private_Functions TS Private Functions + * @{ + */ + + +/** + * @brief Function used to reset all touch data before a new acquisition + * of touch information. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if OK, TE_ERROR if problem found. + */ +uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State) +{ + uint8_t ts_status = TS_ERROR; + uint32_t index; + + if (TS_State != (TS_StateTypeDef *)NULL) + { + TS_State->gestureId = GEST_ID_NO_GESTURE; + TS_State->touchDetected = 0; + + for(index = 0; index < TS_MAX_NB_TOUCH; index++) + { + TS_State->touchX[index] = 0; + TS_State->touchY[index] = 0; + TS_State->touchArea[index] = 0; + TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT; + TS_State->touchWeight[index] = 0; + } + + ts_status = TS_OK; + + } /* of if (TS_State != (TS_StateTypeDef *)NULL) */ + + return (ts_status); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_ts.h b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_ts.h new file mode 100644 index 00000000..1b7d4e60 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery/stm32f7508_discovery_ts.h @@ -0,0 +1,196 @@ +/** + ****************************************************************************** + * @file stm32f7508_discovery_ts.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f7508_discovery_ts.c driver. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7508_DISCOVERY_TS_H +#define __STM32F7508_DISCOVERY_TS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7508_discovery.h" +/* Include touch screen FT5336 component Driver */ +#include "../Components/ft5336/ft5336.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F7508_DISCOVERY_TS + * @{ + */ + + /** @defgroup STM32F7508_DISCOVERY_TS_Exported_Constants STM32F7508_DISCOVERY_TS Exported Constants + * @{ + */ + +/** @brief With FT5336 : maximum 5 touches detected simultaneously + */ +#define TS_MAX_NB_TOUCH ((uint32_t) FT5336_MAX_DETECTABLE_TOUCH) + +#define TS_NO_IRQ_PENDING ((uint8_t) 0) +#define TS_IRQ_PENDING ((uint8_t) 1) + +#define TS_SWAP_NONE ((uint8_t) 0x01) +#define TS_SWAP_X ((uint8_t) 0x02) +#define TS_SWAP_Y ((uint8_t) 0x04) +#define TS_SWAP_XY ((uint8_t) 0x08) + +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_TS_Exported_Types STM32F7508_DISCOVERY_TS Exported Types + * @{ + */ +/** +* @brief TS_StateTypeDef +* Define TS State structure +*/ +typedef struct +{ + uint8_t touchDetected; /*!< Total number of active touches detected at last scan */ + uint16_t touchX[TS_MAX_NB_TOUCH]; /*!< Touch X[0], X[1] coordinates on 12 bits */ + uint16_t touchY[TS_MAX_NB_TOUCH]; /*!< Touch Y[0], Y[1] coordinates on 12 bits */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + uint8_t touchWeight[TS_MAX_NB_TOUCH]; /*!< Touch_Weight[0], Touch_Weight[1] : weight property of touches */ + uint8_t touchEventId[TS_MAX_NB_TOUCH]; /*!< Touch_EventId[0], Touch_EventId[1] : take value of type @ref TS_TouchEventTypeDef */ + uint8_t touchArea[TS_MAX_NB_TOUCH]; /*!< Touch_Area[0], Touch_Area[1] : touch area of each touch */ + uint32_t gestureId; /*!< type of gesture detected : take value of type @ref TS_GestureIdTypeDef */ +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +} TS_StateTypeDef; + +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_TS_Exported_Constants STM32F7508_DISCOVERY_TS Exported Constants + * @{ + */ + +typedef enum +{ + TS_OK = 0x00, /*!< Touch Ok */ + TS_ERROR = 0x01, /*!< Touch Error */ + TS_TIMEOUT = 0x02, /*!< Touch Timeout */ + TS_DEVICE_NOT_FOUND = 0x03 /*!< Touchscreen device not found */ +}TS_StatusTypeDef; + +/** + * @brief TS_GestureIdTypeDef + * Define Possible managed gesture identification values returned by touch screen + * driver. + */ +typedef enum +{ + GEST_ID_NO_GESTURE = 0x00, /*!< Gesture not defined / recognized */ + GEST_ID_MOVE_UP = 0x01, /*!< Gesture Move Up */ + GEST_ID_MOVE_RIGHT = 0x02, /*!< Gesture Move Right */ + GEST_ID_MOVE_DOWN = 0x03, /*!< Gesture Move Down */ + GEST_ID_MOVE_LEFT = 0x04, /*!< Gesture Move Left */ + GEST_ID_ZOOM_IN = 0x05, /*!< Gesture Zoom In */ + GEST_ID_ZOOM_OUT = 0x06, /*!< Gesture Zoom Out */ + GEST_ID_NB_MAX = 0x07 /*!< max number of gesture id */ + +} TS_GestureIdTypeDef; + +/** + * @brief TS_TouchEventTypeDef + * Define Possible touch events kind as returned values + * by touch screen IC Driver. + */ +typedef enum +{ + TOUCH_EVENT_NO_EVT = 0x00, /*!< Touch Event : undetermined */ + TOUCH_EVENT_PRESS_DOWN = 0x01, /*!< Touch Event Press Down */ + TOUCH_EVENT_LIFT_UP = 0x02, /*!< Touch Event Lift Up */ + TOUCH_EVENT_CONTACT = 0x03, /*!< Touch Event Contact */ + TOUCH_EVENT_NB_MAX = 0x04 /*!< max number of touch events kind */ + +} TS_TouchEventTypeDef; +/** + * @} + */ + +/** @defgroup STM32F7508_DISCOVERY_TS_Imported_Variables STM32F7508_DISCOVERY_TS Imported Variables + * @{ + */ +/** + * @brief Table for touchscreen event information display on LCD : + * table indexed on enum @ref TS_TouchEventTypeDef information + */ +extern char * ts_event_string_tab[TOUCH_EVENT_NB_MAX]; + +/** + * @brief Table for touchscreen gesture Id information display on LCD : table indexed + * on enum @ref TS_GestureIdTypeDef information + */ +extern char * ts_gesture_id_string_tab[GEST_ID_NB_MAX]; +/** + * @} + */ + +/** @addtogroup STM32F7508_DISCOVERY_TS_Exported_Functions + * @{ + */ +uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY); +uint8_t BSP_TS_DeInit(void); +uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State); + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State); +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +uint8_t BSP_TS_ITConfig(void); +uint8_t BSP_TS_ITGetStatus(void); +void BSP_TS_ITClear(void); +uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State); +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7508_DISCOVERY_TS_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/Release_Notes.html new file mode 100644 index 00000000..81c5ad01 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/Release_Notes.html @@ -0,0 +1,524 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Release Notes for STM32F769I-Discovery BSP Driver + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for STM32F769I-Discovery  BSP Drivers

+

Copyright +2016 STMicroelectronics

+

+
+

 

+ + + + + + + + + +

+

The BSP (Board Specific +Package) drivers are parts of the STM32Cube package based on the HAL +drivers and provide a set of high level APIs relative to the hardware +components and features in the evaluation boards, discovery kits and nucleo +boards coming with the STM32Cube package for a given STM32 serie.

+

The BSP drivers allow a quick access to the boards’ +services using high level APIs and without any specific configuration as the +link with the HAL and the external components is done in intrinsic within the drivers.
+

+

From project settings points of view, user has only +to add the necessary driver’s files in the workspace and call the needed +functions from examples. However some low level +configuration functions are weak and can be overridden by the applications if user +wants to change some BSP drivers default behavior.

Update History

+ + +

V2.0.1 / 24-August-2017 
+

+ + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • stm32f769i_discovery_lcd.c/.h:
    • Fix compilation errors with SW4STM32 toolchain
    • Add support of second LCD I2C address
  • stm32f769i_discovery_lcd.c:
    • Upgrade version to v2.0.1
  • Add general description of BSP drivers
    +
  • Add Dependencies section
    +
  • Support of PDSC

V2.0.0 / 30-December-2016   

+

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • stm32f769i_discovery_sd.c/.h:
  • +
    • Update BSP SD APIs following new HAL SD drivers implementation
    • +
    • Fix BlockSize to 512 bytes
    • +
  • stm32f769i_discovery_ts.c/.h:
    • Support of FT6336G Touch Screen
  • stm32f769i_discovery_lcd.c/.h:
    • Update BSP_LCD_ReadPixel to read correctely ARGB8888 and RGB888 pixels
  • stm32f769i_discovery_qspi.c/.h:
  • +
      +
    • QSPI write operation improvement
    • +
    • Update CS High Time
    • +
    +
  • Notes:
    +
  • +
      +
    • These BSP drivers break the compatibility with previous versions.
    • +
    • If FatFs is required, "FatFS R0.11 ST modified 20161223" must be used with this version of BSP drivers.
    • +
    +
+

V1.1.0 / 29-August-2016

+ + + + + +

Main +Changes

+ + + +
    +
  • stm32f769i_discovery_lcd.c/.h:
  • +
      +
    • Support of HDMI monitoring
      +
    • +
    +
    • Update DSI initialization
      +
    • Update LTDC clock value
    • Update LCD_DSI_PIXEL_DATA_FMT_RBG888 and LCD_DSI_PIXEL_DATA_FMT_RBG565 values
    +
+

V1.0.1 / 02-June-2016

+ + + + + + + + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • Update typos in drivers comments.

V1.0.0 / 22-April-2016

+ + + + + + + + + + + + + + + + + + + + + + +

Main +Changes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • First official release + of the STM32F769I-Discovery BSP drivers

Dependencies

+ + + + + + +
  • STM32F7xx_HAL_Driver V1.2.0
    +
  • BSP Common V4.0.1

License

+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+

+ + +
+
+

For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32

+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery.c new file mode 100644 index 00000000..34c8314e --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery.c @@ -0,0 +1,818 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery.c + * @author MCD Application Team + * @brief This file provides a set of firmware functions to manage LEDs, + * push-buttons, external SDRAM, external QSPI Flash, RF EEPROM, + * available on STM32F769I-Discovery board (MB1225) from + * STMicroelectronics. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_uart.c +- stm32f7xx_hal_i2c.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL STM32F769I_DISCOVERY LOW LEVEL + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Private_TypesDefinitions STM32F769I Discovery Low Level Private Typedef + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Private_Defines LOW_LEVEL Private Defines + * @{ + */ +/** + * @brief STM32F769I Discovery BSP Driver version number V2.0.1 + */ +#define __STM32F769I_DISCOVERY_BSP_VERSION_MAIN (0x02) /*!< [31:24] main version */ +#define __STM32F769I_DISCOVERY_BSP_VERSION_SUB1 (0x00) /*!< [23:16] sub1 version */ +#define __STM32F769I_DISCOVERY_BSP_VERSION_SUB2 (0x01) /*!< [15:8] sub2 version */ +#define __STM32F769I_DISCOVERY_BSP_VERSION_RC (0x00) /*!< [7:0] release candidate */ +#define __STM32F769I_DISCOVERY_BSP_VERSION ((__STM32F769I_DISCOVERY_BSP_VERSION_MAIN << 24)\ + |(__STM32F769I_DISCOVERY_BSP_VERSION_SUB1 << 16)\ + |(__STM32F769I_DISCOVERY_BSP_VERSION_SUB2 << 8 )\ + |(__STM32F769I_DISCOVERY_BSP_VERSION_RC)) +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Private_Macros LOW_LEVEL Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Private_Variables LOW_LEVEL Private Variables + * @{ + */ +uint32_t GPIO_PIN[LEDn] = {LED1_PIN, + LED2_PIN}; + +GPIO_TypeDef* GPIO_PORT[LEDn] = {LED1_GPIO_PORT, + LED2_GPIO_PORT}; + +GPIO_TypeDef* BUTTON_PORT[BUTTONn] = {WAKEUP_BUTTON_GPIO_PORT }; + +const uint16_t BUTTON_PIN[BUTTONn] = {WAKEUP_BUTTON_PIN }; + +const uint16_t BUTTON_IRQn[BUTTONn] = {WAKEUP_BUTTON_EXTI_IRQn }; + + +static I2C_HandleTypeDef hI2cAudioHandler = {0}; +static I2C_HandleTypeDef hI2cExtHandler = {0}; + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Private_FunctionPrototypes LOW_LEVEL Private FunctionPrototypes + * @{ + */ +static void I2Cx_MspInit(I2C_HandleTypeDef *i2c_handler); +static void I2Cx_Init(I2C_HandleTypeDef *i2c_handler); + +static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static HAL_StatusTypeDef I2Cx_IsDeviceReady(I2C_HandleTypeDef *i2c_handler, uint16_t DevAddress, uint32_t Trials); +static void I2Cx_Error(I2C_HandleTypeDef *i2c_handler, uint8_t Addr); + +/* AUDIO IO functions */ +void AUDIO_IO_Init(void); +void AUDIO_IO_DeInit(void); +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value); +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg); +void AUDIO_IO_Delay(uint32_t Delay); + +/* HDMI IO functions */ +void HDMI_IO_Init(void); +void HDMI_IO_Delay(uint32_t Delay); +void HDMI_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +uint8_t HDMI_IO_Read(uint8_t Addr, uint8_t Reg); + +/* I2C EEPROM IO function */ +void EEPROM_IO_Init(void); +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials); + +/* TouchScreen (TS) IO functions */ +void TS_IO_Init(void); +void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg); +uint16_t TS_IO_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); +void TS_IO_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); +void TS_IO_Delay(uint32_t Delay); + +/* LCD Display IO functions */ +void OTM8009A_IO_Delay(uint32_t Delay); +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_BSP_Public_Functions BSP Public Functions + * @{ + */ + + /** + * @brief This method returns the STM32F769I Discovery BSP Driver revision + * @retval version: 0xXYZR (8bits for each decimal, R for RC) + */ +uint32_t BSP_GetVersion(void) +{ + return __STM32F769I_DISCOVERY_BSP_VERSION; +} + +/** + * @brief Configures LED GPIO. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @retval None + */ +void BSP_LED_Init(Led_TypeDef Led) +{ + GPIO_InitTypeDef gpio_init_structure; + + LEDx_GPIO_CLK_ENABLE(); + /* Configure the GPIO_LED pin */ + gpio_init_structure.Pin = GPIO_PIN[Led]; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + + HAL_GPIO_Init(GPIO_PORT[Led], &gpio_init_structure); + +} + + +/** + * @brief DeInit LEDs. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @note Led DeInit does not disable the GPIO clock + * @retval None + */ +void BSP_LED_DeInit(Led_TypeDef Led) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* DeInit the GPIO_LED pin */ + gpio_init_structure.Pin = GPIO_PIN[Led]; + + /* Turn off LED */ + HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_RESET); + HAL_GPIO_DeInit(GPIO_PORT[Led], gpio_init_structure.Pin); +} + +/** + * @brief Turns selected LED On. + * @param Led: LED to be set on + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @retval None + */ +void BSP_LED_On(Led_TypeDef Led) +{ + HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_SET); +} + +/** + * @brief Turns selected LED Off. + * @param Led: LED to be set off + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @retval None + */ +void BSP_LED_Off(Led_TypeDef Led) +{ + HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_RESET); +} + +/** + * @brief Toggles the selected LED. + * @param Led: LED to be toggled + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @retval None + */ +void BSP_LED_Toggle(Led_TypeDef Led) +{ + HAL_GPIO_TogglePin(GPIO_PORT[Led], GPIO_PIN[Led]); +} + +/** + * @brief Configures button GPIO and EXTI Line. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_USER: User Push Button + * @param Button_Mode: Button mode + * This parameter can be one of the following values: + * @arg BUTTON_MODE_GPIO: Button will be used as simple IO + * @arg BUTTON_MODE_EXTI: Button will be connected to EXTI line + * with interrupt generation capability + * @retval None + */ +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable the BUTTON clock */ + BUTTON_GPIO_CLK_ENABLE(); + + if(Button_Mode == BUTTON_MODE_GPIO) + { + /* Configure Button pin as input */ + gpio_init_structure.Pin = BUTTON_PIN[Button]; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure); + } + + if(Button_Mode == BUTTON_MODE_EXTI) + { + /* Configure Button pin as input with External interrupt */ + gpio_init_structure.Pin = BUTTON_PIN[Button]; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + + gpio_init_structure.Mode = GPIO_MODE_IT_RISING; + + HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure); + + /* Enable and set Button EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(BUTTON_IRQn[Button]), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + } +} + +/** + * @brief Push Button DeInit. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_USER: User Push Button + * @note PB DeInit does not disable the GPIO clock + * @retval None + */ +void BSP_PB_DeInit(Button_TypeDef Button) +{ + GPIO_InitTypeDef gpio_init_structure; + + gpio_init_structure.Pin = BUTTON_PIN[Button]; + HAL_NVIC_DisableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + HAL_GPIO_DeInit(BUTTON_PORT[Button], gpio_init_structure.Pin); +} + + +/** + * @brief Returns the selected button state. + * @param Button: Button to be checked + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_USER: User Push Button + * @retval The Button GPIO pin value + */ +uint32_t BSP_PB_GetState(Button_TypeDef Button) +{ + return HAL_GPIO_ReadPin(BUTTON_PORT[Button], BUTTON_PIN[Button]); +} + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Private_Functions STM32F769I_DISCOVERY_LOW_LEVEL Private Functions + * @{ + */ + + +/******************************************************************************* + BUS OPERATIONS +*******************************************************************************/ + +/******************************* I2C Routines *********************************/ +/** + * @brief Initializes I2C MSP. + * @param i2c_handler : I2C handler + * @retval None + */ +static void I2Cx_MspInit(I2C_HandleTypeDef *i2c_handler) +{ + GPIO_InitTypeDef gpio_init_structure; + + if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cAudioHandler)) + { + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + DISCOVERY_AUDIO_I2Cx_SCL_GPIO_CLK_ENABLE(); + DISCOVERY_AUDIO_I2Cx_SDA_GPIO_CLK_ENABLE(); + /* Configure I2C Tx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_AUDIO_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = DISCOVERY_AUDIO_I2Cx_SCL_AF; + HAL_GPIO_Init(DISCOVERY_AUDIO_I2Cx_SCL_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C Rx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_AUDIO_I2Cx_SDA_PIN; + gpio_init_structure.Alternate = DISCOVERY_AUDIO_I2Cx_SDA_AF; + HAL_GPIO_Init(DISCOVERY_AUDIO_I2Cx_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + DISCOVERY_AUDIO_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + DISCOVERY_AUDIO_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + DISCOVERY_AUDIO_I2Cx_RELEASE_RESET(); + + /* Enable and set I2C1 Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_AUDIO_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_AUDIO_I2Cx_EV_IRQn); + + /* Enable and set I2C1 Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_AUDIO_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_AUDIO_I2Cx_ER_IRQn); + + } + else + { + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_CLK_ENABLE(); + + /* Configure I2C Tx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_EXT_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = DISCOVERY_EXT_I2Cx_SCL_SDA_AF; + HAL_GPIO_Init(DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C Rx as alternate function */ + gpio_init_structure.Pin = DISCOVERY_EXT_I2Cx_SDA_PIN; + HAL_GPIO_Init(DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + DISCOVERY_EXT_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + DISCOVERY_EXT_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + DISCOVERY_EXT_I2Cx_RELEASE_RESET(); + + /* Enable and set I2C1 Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_EXT_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_EXT_I2Cx_EV_IRQn); + + /* Enable and set I2C1 Interrupt to a lower priority */ + HAL_NVIC_SetPriority(DISCOVERY_EXT_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DISCOVERY_EXT_I2Cx_ER_IRQn); + } +} + +/** + * @brief Initializes I2C HAL. + * @param i2c_handler : I2C handler + * @retval None + */ +static void I2Cx_Init(I2C_HandleTypeDef *i2c_handler) +{ + if(HAL_I2C_GetState(i2c_handler) == HAL_I2C_STATE_RESET) + { + if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cAudioHandler)) + { + /* Audio and LCD I2C configuration */ + i2c_handler->Instance = DISCOVERY_AUDIO_I2Cx; + } + else + { + /* External, camera and Arduino connector I2C configuration */ + i2c_handler->Instance = DISCOVERY_EXT_I2Cx; + } + i2c_handler->Init.Timing = DISCOVERY_I2Cx_TIMING; + i2c_handler->Init.OwnAddress1 = 0; + i2c_handler->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + i2c_handler->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + i2c_handler->Init.OwnAddress2 = 0; + i2c_handler->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + i2c_handler->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + + /* Init the I2C */ + I2Cx_MspInit(i2c_handler); + HAL_I2C_Init(i2c_handler); + } +} + +/** + * @brief Reads multiple data. + * @param i2c_handler : I2C handler + * @param Addr: I2C address + * @param Reg: Reg address + * @param MemAddress: memory address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddress, uint8_t *Buffer, uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Read(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* I2C error occured */ + I2Cx_Error(i2c_handler, Addr); + } + return status; +} + + +/** + * @brief Writes a value in a register of the device through BUS in using DMA mode. + * @param i2c_handler : I2C handler + * @param Addr: Device address on BUS Bus. + * @param Reg: The target register address to write + * @param MemAddress: memory address + * @param Buffer: The target register value to be written + * @param Length: buffer size to be written + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddress, uint8_t *Buffer, uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Write(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* Re-Initiaize the I2C Bus */ + I2Cx_Error(i2c_handler, Addr); + } + return status; +} + +/** + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param i2c_handler : I2C handler + * @param DevAddress: Target device address + * @param Trials: Number of trials + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_IsDeviceReady(I2C_HandleTypeDef *i2c_handler, uint16_t DevAddress, uint32_t Trials) +{ + return (HAL_I2C_IsDeviceReady(i2c_handler, DevAddress, Trials, 1000)); +} + +/** + * @brief Manages error callback by re-initializing I2C. + * @param i2c_handler : I2C handler + * @param Addr: I2C Address + * @retval None + */ +static void I2Cx_Error(I2C_HandleTypeDef *i2c_handler, uint8_t Addr) +{ + /* De-initialize the I2C communication bus */ + HAL_I2C_DeInit(i2c_handler); + + /* Re-Initialize the I2C communication bus */ + I2Cx_Init(i2c_handler); +} + +/** + * @} + */ + +/******************************************************************************* + LINK OPERATIONS +*******************************************************************************/ + +/********************************* LINK AUDIO *********************************/ + +/** + * @brief Initializes Audio low level. + */ +void AUDIO_IO_Init(void) +{ + I2Cx_Init(&hI2cAudioHandler); +} + +/** + * @brief DeInitializes Audio low level. + */ +void AUDIO_IO_DeInit(void) +{ + +} + +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param Value: Data to be written + * @retval None + */ +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value) +{ + uint16_t tmp = Value; + + Value = ((uint16_t)(tmp >> 8) & 0x00FF); + + Value |= ((uint16_t)(tmp << 8)& 0xFF00); + + I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_16BIT,(uint8_t*)&Value, 2); +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @retval Data to be read + */ +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg) +{ + uint16_t read_value = 0, tmp = 0; + + I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&read_value, 2); + + tmp = ((uint16_t)(read_value >> 8) & 0x00FF); + + tmp |= ((uint16_t)(read_value << 8)& 0xFF00); + + read_value = tmp; + + return read_value; +} + +/** + * @brief AUDIO Codec delay + * @param Delay: Delay in ms + */ +void AUDIO_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/******************************** LINK I2C EEPROM *****************************/ + +/** + * @brief Initializes peripherals used by the I2C EEPROM driver. + */ +void EEPROM_IO_Init(void) +{ + I2Cx_Init(&hI2cExtHandler); +} + +/** + * @brief Write data to I2C EEPROM driver in using DMA channel. + * @param DevAddress: Target device address + * @param MemAddress: Internal memory address + * @param pBuffer: Pointer to data buffer + * @param BufferSize: Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize) +{ + return (I2Cx_WriteMultiple(&hI2cExtHandler, DevAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, pBuffer, BufferSize)); +} + +/** + * @brief Read data from I2C EEPROM driver in using DMA channel. + * @param DevAddress: Target device address + * @param MemAddress: Internal memory address + * @param pBuffer: Pointer to data buffer + * @param BufferSize: Amount of data to be read + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize) +{ + return (I2Cx_ReadMultiple(&hI2cExtHandler, DevAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, pBuffer, BufferSize)); +} + +/** + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param DevAddress: Target device address + * @param Trials: Number of trials + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials) +{ + return (I2Cx_IsDeviceReady(&hI2cExtHandler, DevAddress, Trials)); +} + +/******************************** LINK TS (TouchScreen) ***********************/ + +/** + * @brief Initializes Touchscreen low level. + * @retval None + */ +void TS_IO_Init(void) +{ + I2Cx_Init(&hI2cAudioHandler); +} + +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param Value: Data to be written + * @retval None + */ +void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT,(uint8_t*)&Value, 1); +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @retval Data to be read + */ +uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg) +{ + uint8_t read_value = 0; + + I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&read_value, 1); + + return read_value; +} + +/** + * @brief Reads multiple data with I2C communication + * channel from TouchScreen. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval Number of read data + */ +uint16_t TS_IO_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + return I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief Writes multiple data with I2C communication + * channel from MCU to TouchScreen. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval None + */ +void TS_IO_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief Delay function used in TouchScreen low level driver. + * @param Delay: Delay in ms + * @retval None + */ +void TS_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/**************************** LINK OTM8009A (Display driver) ******************/ +/** + * @brief OTM8009A delay + * @param Delay: Delay in ms + */ +void OTM8009A_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/**************************** LINK ADV7533 DSI-HDMI (Display driver) **********/ +/** + * @brief Initializes HDMI IO low level. + * @retval None + */ +void HDMI_IO_Init(void) +{ + I2Cx_Init(&hI2cAudioHandler); +} + +/** + * @brief HDMI writes single data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Value: Data to be written + * @retval None + */ +void HDMI_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, &Value, 1); +} + +/** + * @brief Reads single data with I2C communication + * channel from HDMI bridge. + * @param Addr: I2C address + * @param Reg: Register address + * @retval Read data + */ +uint8_t HDMI_IO_Read(uint8_t Addr, uint8_t Reg) +{ + uint8_t value = 0x00; + + I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, &value, 1); + + return value; +} + +/** + * @brief HDMI delay + * @param Delay: Delay in ms + * @retval None + */ +void HDMI_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery.h new file mode 100644 index 00000000..c183d1ee --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery.h @@ -0,0 +1,352 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery.h + * @author MCD Application Team + * @brief This file contains definitions for STM32F769I-Discovery LEDs, + * push-buttons hardware resources. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_DISCOVERY_H +#define __STM32F769I_DISCOVERY_H + +#ifdef __cplusplus + extern "C" { +#endif + + + /* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL STM32F769I-Discovery LOW LEVEL + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Exported_Types STM32F769I Discovery Low Level Exported Types + * @{ + */ + +/** + * @brief Define for STM32F769I_DISCOVERY board + */ +#if !defined (USE_STM32F769I_DISCO) + #define USE_STM32F769I_DISCO +#endif + +/** @brief Led_TypeDef + * STM32F769I_DISCOVERY board leds definitions. + */ +typedef enum +{ + LED1 = 0, + LED_RED = LED1, + LED2 = 1, + LED_GREEN = LED2 +} Led_TypeDef; + +/** @brief Button_TypeDef + * STM32F769I_DISCOVERY board Buttons definitions. + */ +typedef enum +{ + BUTTON_WAKEUP = 0, +} Button_TypeDef; + +#define BUTTON_USER BUTTON_WAKEUP + +/** @brief ButtonMode_TypeDef + * STM32F769I_DISCOVERY board Buttons Modes definitions. + */ +typedef enum +{ + BUTTON_MODE_GPIO = 0, + BUTTON_MODE_EXTI = 1 + +} ButtonMode_TypeDef; + +/** @addtogroup Exported_types + * @{ + */ +typedef enum +{ + PB_SET = 0, + PB_RESET = !PB_SET +} ButtonValue_TypeDef; + + +/** @brief DISCO_Status_TypeDef + * STM32F769I_DISCO board Status return possible values. + */ +typedef enum +{ + DISCO_OK = 0, + DISCO_ERROR = 1 + +} DISCO_Status_TypeDef; + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Exported_Constants STM32F769I Discovery Low Level Exported Constants + * @{ + */ + + +/** @addtogroup STM32F769I_DISCOVERY_LOW_LEVEL_LED STM32F769I Discovery Low Level Led + * @{ + */ +/* Always four leds for all revisions of Discovery boards */ +#define LEDn ((uint8_t)2) + + +/* 2 Leds are connected to MCU directly on PJ13 and PJ5 */ +#define LED1_GPIO_PORT ((GPIO_TypeDef*)GPIOJ) +#define LED2_GPIO_PORT ((GPIO_TypeDef*)GPIOJ) + +#define LEDx_GPIO_CLK_ENABLE() __HAL_RCC_GPIOJ_CLK_ENABLE() +#define LEDx_GPIO_CLK_DISABLE() __HAL_RCC_GPIOJ_CLK_DISABLE() + +#define LED1_PIN ((uint32_t)GPIO_PIN_13) +#define LED2_PIN ((uint32_t)GPIO_PIN_5) + +/** + * @} + */ + +/** @addtogroup STM32F769I_DISCOVERY_LOW_LEVEL_BUTTON STM32F769I Discovery Low Level Button + * @{ + */ +/* Only one User/Wakeup button */ +#define BUTTONn ((uint8_t)1) + +/** + * @brief Wakeup push-button + */ +#define WAKEUP_BUTTON_PIN GPIO_PIN_0 +#define WAKEUP_BUTTON_GPIO_PORT GPIOA +#define WAKEUP_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define WAKEUP_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define WAKEUP_BUTTON_EXTI_IRQn EXTI0_IRQn + +/* Define the USER button as an alias of the Wakeup button */ +#define USER_BUTTON_PIN WAKEUP_BUTTON_PIN +#define USER_BUTTON_GPIO_PORT WAKEUP_BUTTON_GPIO_PORT +#define USER_BUTTON_GPIO_CLK_ENABLE() WAKEUP_BUTTON_GPIO_CLK_ENABLE() +#define USER_BUTTON_GPIO_CLK_DISABLE() WAKEUP_BUTTON_GPIO_CLK_DISABLE() +#define USER_BUTTON_EXTI_IRQn WAKEUP_BUTTON_EXTI_IRQn + +#define BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() + +/** + * @} + */ + +/** + * @brief USB OTG HS Over Current signal + */ +#define OTG_HS_OVER_CURRENT_PIN GPIO_PIN_4 +#define OTG_HS_OVER_CURRENT_PORT GPIOD +#define OTG_HS_OVER_CURRENT_PORT_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() + +/** + * @brief SD-detect signal + */ +#define SD_DETECT_PIN ((uint32_t)GPIO_PIN_15) +#define SD_DETECT_GPIO_PORT ((GPIO_TypeDef*)GPIOI) +#define SD_DETECT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define SD_DETECT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define SD_DETECT_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief Touch screen interrupt signal + */ +#define TS_INT_PIN ((uint32_t)GPIO_PIN_13) +#define TS_INT_GPIO_PORT ((GPIO_TypeDef*)GPIOI) +#define TS_INT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define TS_INT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define TS_INT_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief TouchScreen FT6206 Slave I2C address 1 + */ +#define TS_I2C_ADDRESS ((uint16_t)0x54) + +/** + * @brief TouchScreen FT6336G Slave I2C address 2 + */ +#define TS_I2C_ADDRESS_A02 ((uint16_t)0x70) + +/** + * @brief LCD DSI Slave I2C address 1 + */ +#define LCD_DSI_ADDRESS TS_I2C_ADDRESS + +/** + * @brief LCD DSI Slave I2C address 2 + */ +#define LCD_DSI_ADDRESS_A02 TS_I2C_ADDRESS_A02 + +/** + * @brief Audio I2C Slave address + */ +#define AUDIO_I2C_ADDRESS ((uint16_t)0x34) + +/** + * @brief EEPROM I2C Slave address 1 + */ +#define EEPROM_I2C_ADDRESS_A01 ((uint16_t)0xA0) + +/** + * @brief EEPROM I2C Slave address 2 + */ +#define EEPROM_I2C_ADDRESS_A02 ((uint16_t)0xA6) + +/** + * @brief User can use this section to tailor I2C4/I2C4 instance used and associated + * resources (audio codec). + * Definition for I2C4 clock resources + */ +#define DISCOVERY_AUDIO_I2Cx I2C4 +#define DISCOVERY_AUDIO_I2Cx_CLK_ENABLE() __HAL_RCC_I2C4_CLK_ENABLE() +#define DISCOVERY_AUDIO_I2Cx_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() +#define DISCOVERY_AUDIO_I2Cx_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() + +#define DISCOVERY_AUDIO_I2Cx_FORCE_RESET() __HAL_RCC_I2C4_FORCE_RESET() +#define DISCOVERY_AUDIO_I2Cx_RELEASE_RESET() __HAL_RCC_I2C4_RELEASE_RESET() + +/** @brief Definition for I2C4 Pins + */ +#define DISCOVERY_AUDIO_I2Cx_SCL_PIN GPIO_PIN_12 /*!< PD12 */ +#define DISCOVERY_AUDIO_I2Cx_SCL_AF GPIO_AF4_I2C4 +#define DISCOVERY_AUDIO_I2Cx_SCL_GPIO_PORT GPIOD +#define DISCOVERY_AUDIO_I2Cx_SDA_PIN GPIO_PIN_7 /*!< PB7 */ +#define DISCOVERY_AUDIO_I2Cx_SDA_AF GPIO_AF11_I2C4 +#define DISCOVERY_AUDIO_I2Cx_SDA_GPIO_PORT GPIOB +/** @brief Definition of I2C4 interrupt requests + */ +#define DISCOVERY_AUDIO_I2Cx_EV_IRQn I2C4_EV_IRQn +#define DISCOVERY_AUDIO_I2Cx_ER_IRQn I2C4_ER_IRQn + +/** + * @brief User can use this section to tailor I2C1/I2C1 instance used and associated + * resources. + * Definition for I2C1 clock resources + */ +#define DISCOVERY_EXT_I2Cx I2C1 +#define DISCOVERY_EXT_I2Cx_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE() +#define DISCOVERY_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE() +#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() + +#define DISCOVERY_EXT_I2Cx_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET() +#define DISCOVERY_EXT_I2Cx_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET() + +/** @brief Definition for I2C1 Pins + */ +#define DISCOVERY_EXT_I2Cx_SCL_PIN GPIO_PIN_8 /*!< PB8 */ +#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT GPIOB +#define DISCOVERY_EXT_I2Cx_SCL_SDA_AF GPIO_AF4_I2C1 +#define DISCOVERY_EXT_I2Cx_SDA_PIN GPIO_PIN_9 /*!< PB9 */ + +/** @brief Definition of I2C interrupt requests + */ +#define DISCOVERY_EXT_I2Cx_EV_IRQn I2C1_EV_IRQn +#define DISCOVERY_EXT_I2Cx_ER_IRQn I2C1_ER_IRQn + +/* I2C TIMING Register define when I2C clock source is SYSCLK */ +/* I2C TIMING is calculated from APB1 source clock = 50 MHz */ +/* Due to the big MOFSET capacity for adapting the camera level the rising time is very large (>1us) */ +/* 0x40912732 takes in account the big rising and aims a clock of 100khz */ +#ifndef DISCOVERY_I2Cx_TIMING +#define DISCOVERY_I2Cx_TIMING ((uint32_t)0x40912732) +#endif /* DISCOVERY_I2Cx_TIMING */ + + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Exported_Macros STM32F769I Discovery Low Level Exported Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Exported_Functions STM32F769I Discovery Low Level Exported Functions + * @{ + */ +uint32_t BSP_GetVersion(void); +void BSP_LED_Init(Led_TypeDef Led); +void BSP_LED_DeInit(Led_TypeDef Led); +void BSP_LED_On(Led_TypeDef Led); +void BSP_LED_Off(Led_TypeDef Led); +void BSP_LED_Toggle(Led_TypeDef Led); +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode); +void BSP_PB_DeInit(Button_TypeDef Button); +uint32_t BSP_PB_GetState(Button_TypeDef Button); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_DISCOVERY_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_audio.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_audio.c new file mode 100644 index 00000000..a4f711e0 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_audio.c @@ -0,0 +1,2212 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_audio.c + * @author MCD Application Team + * @brief This file provides the Audio driver for the STM32F769I-DISCOVERY + * board. + @verbatim + How To use this driver: + ----------------------- + + This driver supports STM32F7xx devices on STM32F769I-DISCOVERY (MB1225) Evaluation boards. + + Call the function BSP_AUDIO_OUT_Init( + OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, + OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH) + Volume : Initial volume to be set (0 is min (mute), 100 is max (100%) + AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...) + this parameter is relative to the audio file/stream type. + ) + This function configures all the hardware required for the audio application (codec, I2C, SAI, + GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK. + If the returned value is different from AUDIO_OK or the function is stuck then the communication with + the codec has failed (try to un-plug the power or reset device in this case). + - OUTPUT_DEVICE_SPEAKER : only speaker will be set as output for the audio stream. + - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream. + - OUTPUT_DEVICE_BOTH : both Speaker and Headphone are used as outputs for the audio stream + at the same time. + Note. On STM32F769I-DISCOVERY SAI_DMA is configured in CIRCULAR mode. Due to this the application + does NOT need to call BSP_AUDIO_OUT_ChangeBuffer() to assure streaming. + + Call the function BSP_AUDIO_OUT_Play( + pBuffer: pointer to the audio data file address + Size : size of the buffer to be sent in Bytes + ) + to start playing (for the first time) from the audio file/stream. + + Call the function BSP_AUDIO_OUT_Pause() to pause playing + + Call the function BSP_AUDIO_OUT_Resume() to resume playing. + Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called + for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case). + Note. This function should be called only when the audio file is played or paused (not stopped). + + For each mode, you may need to implement the relative callback functions into your code. + The Callback functions are named BSP_AUDIO_OUT_XXX_CallBack() and only their prototypes are declared in + the stm32f769i_discovery_audio.h file. (refer to the example for more details on the callbacks implementations) + + To Stop playing, to modify the volume level, the frequency, the audio frame slot, + the device output mode the mute or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(), + AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetAudioFrameSlot(), BSP_AUDIO_OUT_SetOutputMode(), + BSP_AUDIO_OUT_SetMute() and BSP_AUDIO_OUT_Stop(). + + + Call the function BSP_AUDIO_IN_Init( + AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000...) + this parameter is relative to the audio file/stream type. + BitRes: Bit resolution fixed to 16bit + ChnlNbr: Number of channel to be configured for the DFSDM peripheral + ) + This function configures all the hardware required for the audio in application (DFSDM filters and channels, + Clock source for DFSDM periphiral, GPIOs, DMA and interrupt if needed). + This function returns AUDIO_OK if configuration is OK.If the returned value is different from AUDIO_OK then + the configuration should be wrong. + Note: On STM32F769I-DISCOVERY, four DFSDM Channel/Filters are configured and their DMA streams are configured + in CIRCULAR mode. + + Call the function BSP_AUDIO_IN_AllocScratch( + pScratch: pointer to scratch tables + size: size of scratch buffer) + This function must be called before BSP_AUDIO_IN_RECORD() to allocate buffer scratch for each DFSDM channel + and its size. + Note: These buffers scratch are used as intermidiate buffers to collect data within final record buffer. + size is the total size of the four buffers scratch; If size is 512 then the size of each is 128. + This function must be called after BSP_AUDIO_IN_Init() + + Call the function BSP_AUDIO_IN_RECORD( + pBuf: pointer to the recorded audio data file address + Size: size of the buffer to be written in Bytes + ) + to start recording from microphones. + + + Call the function BSP_AUDIO_IN_Pause() to pause recording + + Call the function BSP_AUDIO_IN_Resume() to recording playing. + Note. After calling BSP_AUDIO_IN_Pause() function for pause, only BSP_AUDIO_IN_Resume() should be called + for resume (it is not allowed to call BSP_AUDIO_IN_RECORD() in this case). + + Call the function BSP_AUDIO_IN_Stop() to stop recording + + For each mode, you may need to implement the relative callback functions into your code. + The Callback functions are named BSP_AUDIO_IN_XXX_CallBack() and only their prototypes are declared in + the stm32f769i_discovery_audio.h file. (refer to the example for more details on the callbacks implementations) + + Driver architecture: + -------------------- + + This driver provides the High Audio Layer: consists of the function API exported in the stm32f769i_discovery_audio.h file + (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...) + + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/ + providing the audio file/stream. These functions are also included as local functions into + the stm32f769i_discovery_audio.c file (DFSDMx_Init(), DFSDMx_DeInit(), SAIx_Init() and SAIx_DeInit()) + + Known Limitations: + ------------------ + 1- If the TDM Format used to play in parallel 2 audio Stream (the first Stream is configured in codec SLOT0 and second + Stream in SLOT1) the Pause/Resume, volume and mute feature will control the both streams. + 2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, + File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file. + 3- Supports only Stereo audio streaming. + 4- Supports only 16-bits audio data size. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f769i_discovery.c +- stm32f7xx_hal_sai.c +- stm32f7xx_hal_dfsdm.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- wm8994.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_discovery_audio.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO STM32F769I_DISCOVERY AUDIO + * @brief This file includes the low layer driver for wm8994 Audio Codec + * available on STM32F769I-DISCOVERY discoveryuation board(MB1225). + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO_Private_Types STM32F769I_DISCOVERY_AUDIO Private Types + * @{ + */ +typedef struct +{ + uint16_t *pRecBuf; /* Pointer to record user buffer */ + uint32_t RecSize; /* Size to record in mono, double size to record in stereo */ +}AUDIOIN_TypeDef; + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO_Private_Defines STM32F769I_DISCOVERY_AUDIO Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO_Private_Macros STM32F769I_DISCOVERY_AUDIO Private Macros + * @{ + */ +/*### RECORD ###*/ +#define DFSDM_OVER_SAMPLING(__FREQUENCY__) \ + (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 256 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 256 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 128 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 128 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 64 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 64 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 40 : 20 \ + +#define DFSDM_CLOCK_DIVIDER(__FREQUENCY__) \ + (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 24 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 4 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 24 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 4 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 24 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 4 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 25 : 25 \ + +#define DFSDM_FILTER_ORDER(__FREQUENCY__) \ + (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? DFSDM_FILTER_SINC3_ORDER \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? DFSDM_FILTER_SINC3_ORDER \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? DFSDM_FILTER_SINC3_ORDER \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? DFSDM_FILTER_SINC3_ORDER \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? DFSDM_FILTER_SINC4_ORDER \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? DFSDM_FILTER_SINC3_ORDER \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? DFSDM_FILTER_SINC3_ORDER : DFSDM_FILTER_SINC5_ORDER \ + +#define DFSDM_RIGHT_BIT_SHIFT(__FREQUENCY__) \ + (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 8 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 8 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 3 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 4 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 7 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 0 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 0 : 4 \ + +/* Saturate the record PCM sample */ +#define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N))) +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO_Private_Variables STM32F769I_DISCOVERY_AUDIO Private Variables + * @{ + */ +/* PLAY */ +AUDIO_DrvTypeDef *audio_drv; +SAI_HandleTypeDef haudio_out_sai; +SAI_HandleTypeDef haudio_in_sai; + +/* RECORD */ +AUDIOIN_TypeDef hAudioIn; + +DFSDM_Channel_HandleTypeDef hAudioInTopLeftChannel; +DFSDM_Channel_HandleTypeDef hAudioInTopRightChannel; +DFSDM_Filter_HandleTypeDef hAudioInTopLeftFilter; +DFSDM_Filter_HandleTypeDef hAudioInTopRightFilter; +DMA_HandleTypeDef hDmaTopLeft; +DMA_HandleTypeDef hDmaTopRight; + +DFSDM_Channel_HandleTypeDef hAudioInButtomLeftChannel; +DFSDM_Channel_HandleTypeDef hAudioInButtomRightChannel; +DFSDM_Filter_HandleTypeDef hAudioInButtomLeftFilter; +DFSDM_Filter_HandleTypeDef hAudioInButtomRightFilter; +DMA_HandleTypeDef hDmaButtomLeft; +DMA_HandleTypeDef hDmaButtomRight; + +/* Buffers for right and left samples */ +static int32_t *pScratchBuff[2*DEFAULT_AUDIO_IN_CHANNEL_NBR]; +static __IO int32_t ScratchSize; +/* Cannel number to be used: 2 channels by default */ +static uint8_t AudioIn_ChannelNumber = DEFAULT_AUDIO_IN_CHANNEL_NBR; +/* Input device to be used: digital microphones by default */ +static uint16_t AudioIn_Device = INPUT_DEVICE_DIGITAL_MIC; + +/* Buffers status flags */ +static uint32_t DmaTopLeftRecHalfCplt = 0; +static uint32_t DmaTopLeftRecCplt = 0; +static uint32_t DmaTopRightRecHalfCplt = 0; +static uint32_t DmaTopRightRecCplt = 0; +static uint32_t DmaButtomLeftRecHalfCplt = 0; +static uint32_t DmaButtomLeftRecCplt = 0; +static uint32_t DmaButtomRightRecHalfCplt = 0; +static uint32_t DmaButtomRightRecCplt = 0; + +/* Application Buffer Trigger */ +static __IO uint32_t AppBuffTrigger = 0; +static __IO uint32_t AppBuffHalf = 0; + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO_Private_Function_Prototypes STM32F769I_DISCOVERY_AUDIO Private Function Prototypes + * @{ + */ +static void SAIx_Out_Init(uint32_t AudioFreq); +static void SAIx_Out_DeInit(void); +static void SAI_AUDIO_IN_MspInit(SAI_HandleTypeDef *hsai, void *Params); +static void SAI_AUDIO_IN_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); +static void SAIx_In_Init(uint32_t AudioFreq); +static void SAIx_In_DeInit(void); +static void DFSDMx_ChannelMspInit(void); +static void DFSDMx_FilterMspInit(void); +static void DFSDMx_ChannelMspDeInit(void); +static void DFSDMx_FilterMspDeInit(void); +static uint8_t DFSDMx_Init(uint32_t AudioFreq); +static uint8_t DFSDMx_DeInit(void); + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO_out_Private_Functions STM32F769I_DISCOVERY_AUDIO_Out Private Functions + * @{ + */ + +/** + * @brief Configures the audio peripherals. + * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * or OUTPUT_DEVICE_BOTH. + * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) + * @param AudioFreq: Audio frequency used to play the audio stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq) +{ + uint8_t ret = AUDIO_ERROR; + uint32_t deviceid = 0x00; + + /* Disable SAI */ + SAIx_Out_DeInit(); + + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); + } + SAIx_Out_Init(AudioFreq); + + /* wm8994 codec initialization */ + deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); + + if((deviceid) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq); + } + + return ret; +} + +/** + * @brief Starts playing audio stream from a data buffer for a determined size. + * @param pBuffer: Pointer to the buffer + * @param Size: Number of audio data BYTES. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size) +{ + /* Call the audio Codec Play function */ + if(audio_drv->Play(AUDIO_I2C_ADDRESS, (uint16_t *)pBuffer, Size) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Update the Media layer and enable it for play */ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, DMA_MAX(Size / AUDIODATA_SIZE)); + + return AUDIO_OK; + } +} + +/** + * @brief Sends n-Bytes on the SAI interface. + * @param pData: pointer on data address + * @param Size: number of data to be written + * @retval None + */ +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size) +{ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pData, Size); +} + +/** + * @brief This function Pauses the audio file stream. In case + * of using DMA, the DMA Pause feature is used. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Pause(void) +{ + /* Call the Audio Codec Pause/Resume function */ + if(audio_drv->Pause(AUDIO_I2C_ADDRESS) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause function */ + HAL_SAI_DMAPause(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Resumes the audio file stream. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Resume(void) +{ + /* Call the Audio Codec Pause/Resume function */ + if(audio_drv->Resume(AUDIO_I2C_ADDRESS) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause/resume function */ + HAL_SAI_DMAResume(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Stops audio playing and Power down the Audio Codec. + * @param Option: could be one of the following parameters + * - CODEC_PDWN_SW: for software power off (by writing registers). + * Then no need to reconfigure the Codec after power on. + * - CODEC_PDWN_HW: completely shut down the codec (physically). + * Then need to reconfigure the Codec after power on. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option) +{ + /* Call the Media layer stop function */ + HAL_SAI_DMAStop(&haudio_out_sai); + + /* Call Audio Codec Stop function */ + if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) + { + return AUDIO_ERROR; + } + else + { + if(Option == CODEC_PDWN_HW) + { + /* Wait at least 100us */ + HAL_Delay(1); + } + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Controls the current audio volume level. + * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for + * Mute and 100 for Max volume level). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume) +{ + /* Call the codec volume control function with converted volume value */ + if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Enables or disables the MUTE mode by software + * @param Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to + * unmute the codec and restore previous volume level. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd) +{ + /* Call the Codec Mute function */ + if(audio_drv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Switch dynamically (while audio file is played) the output target + * (speaker or headphone). + * @param Output: The audio output target: OUTPUT_DEVICE_SPEAKER, + * OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output) +{ + /* Call the Codec output device function */ + if(audio_drv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Updates the audio frequency. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frequency. + * @retval None + */ +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq) +{ + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frequency configuration */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Updates the Audio frame slot configuration. + * @param AudioFrameSlot: specifies the audio Frame slot + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frame slot. + * @retval None + */ +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot) +{ + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frame slot configuration */ + haudio_out_sai.SlotInit.SlotActive = AudioFrameSlot; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief De-initializes the audio out peripheral. + * @retval None + */ +void BSP_AUDIO_OUT_DeInit(void) +{ + SAIx_Out_DeInit(); + /* DeInit the SAI MSP : this __weak function can be rewritten by the application */ + BSP_AUDIO_OUT_MspDeInit(&haudio_out_sai, NULL); +} + +/** + * @brief Tx Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f769i_discovery_audio.h) */ + BSP_AUDIO_OUT_TransferComplete_CallBack(); +} + +/** + * @brief Tx Half Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f769i_discovery_audio.h) */ + BSP_AUDIO_OUT_HalfTransfer_CallBack(); +} + +/** + * @brief SAI error callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai) +{ + if(hsai->Instance == AUDIO_OUT_SAIx) + { + BSP_AUDIO_OUT_Error_CallBack(); + } + else + { + BSP_AUDIO_IN_Error_CallBack(); + } +} + +/** + * @brief Manages the DMA full Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void) +{ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void) +{ +} + +/** + * @brief Manages the DMA FIFO error event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_Error_CallBack(void) +{ +} + +/** + * @brief Initializes BSP_AUDIO_OUT MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params) +{ + static DMA_HandleTypeDef hdma_sai_tx; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SAI clock */ + AUDIO_OUT_SAIx_CLK_ENABLE(); + + + /* Enable GPIO clock */ + AUDIO_OUT_SAIx_MCLK_ENABLE(); + AUDIO_OUT_SAIx_SD_FS_CLK_ENABLE(); + + /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/ + gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN | AUDIO_OUT_SAIx_SCK_PIN | AUDIO_OUT_SAIx_SD_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = AUDIO_OUT_SAIx_AF; + HAL_GPIO_Init(AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN; + HAL_GPIO_Init(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, &gpio_init_structure); + + /* Enable the DMA clock */ + AUDIO_OUT_SAIx_DMAx_CLK_ENABLE(); + + if(hsai->Instance == AUDIO_OUT_SAIx) + { + /* Configure the hdma_saiTx handle parameters */ + hdma_sai_tx.Init.Channel = AUDIO_OUT_SAIx_DMAx_CHANNEL; + hdma_sai_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_sai_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sai_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sai_tx.Init.PeriphDataAlignment = AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE; + hdma_sai_tx.Init.MemDataAlignment = AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE; + hdma_sai_tx.Init.Mode = DMA_CIRCULAR; + hdma_sai_tx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_sai_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + hdma_sai_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sai_tx.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_sai_tx.Init.PeriphBurst = DMA_PBURST_SINGLE; + + hdma_sai_tx.Instance = AUDIO_OUT_SAIx_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsai, hdmatx, hdma_sai_tx); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_tx); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hdma_sai_tx); + } + + /* SAI DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_OUT_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ); +} + +/** + * @brief Initializes SAI Audio IN MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +static void SAI_AUDIO_IN_MspInit(SAI_HandleTypeDef *hsai, void *Params) +{ + static DMA_HandleTypeDef hdma_sai_rx; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SAI clock */ + AUDIO_IN_SAIx_CLK_ENABLE(); + + /* Enable SD GPIO clock */ + AUDIO_IN_SAIx_SD_ENABLE(); + /* CODEC_SAI pin configuration: SD pin */ + gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Alternate = AUDIO_IN_SAIx_AF; + HAL_GPIO_Init(AUDIO_IN_SAIx_SD_GPIO_PORT, &gpio_init_structure); + + /* Enable Audio INT GPIO clock */ + AUDIO_IN_INT_GPIO_ENABLE(); + /* Audio INT pin configuration: input */ + gpio_init_structure.Pin = AUDIO_IN_INT_GPIO_PIN; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + HAL_GPIO_Init(AUDIO_IN_INT_GPIO_PORT, &gpio_init_structure); + + /* Enable the DMA clock */ + AUDIO_IN_SAIx_DMAx_CLK_ENABLE(); + + if(hsai->Instance == AUDIO_IN_SAIx) + { + /* Configure the hdma_sai_rx handle parameters */ + hdma_sai_rx.Init.Channel = AUDIO_IN_SAIx_DMAx_CHANNEL; + hdma_sai_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_sai_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sai_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sai_rx.Init.PeriphDataAlignment = AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE; + hdma_sai_rx.Init.MemDataAlignment = AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE; + hdma_sai_rx.Init.Mode = DMA_CIRCULAR; + hdma_sai_rx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_sai_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_sai_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sai_rx.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_sai_rx.Init.PeriphBurst = DMA_MBURST_SINGLE; + + hdma_sai_rx.Instance = AUDIO_IN_SAIx_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsai, hdmarx, hdma_sai_rx); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_rx); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hdma_sai_rx); + } + + /* SAI DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_IN_SAIx_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_IN_SAIx_DMAx_IRQ); + + /* Audio INT IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_IN_INT_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_IN_INT_IRQ); +} + +/** + * @brief De-Initializes SAI Audio IN MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +static void SAI_AUDIO_IN_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* SAI DMA IRQ Channel deactivation */ + HAL_NVIC_DisableIRQ(AUDIO_IN_SAIx_DMAx_IRQ); + + if(hsai->Instance == AUDIO_IN_SAIx) + { + /* Deinitialize the DMA stream */ + HAL_DMA_DeInit(hsai->hdmatx); + } + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(hsai); + + /* Deactivates CODEC_SAI pin SD by putting them in input mode */ + gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN; + HAL_GPIO_DeInit(AUDIO_IN_SAIx_SD_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_IN_INT_GPIO_PIN; + HAL_GPIO_DeInit(AUDIO_IN_INT_GPIO_PORT, gpio_init_structure.Pin); + + /* Disable SAI clock */ + AUDIO_IN_SAIx_CLK_DISABLE(); +} + +/** + * @brief Deinitializes SAI MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* SAI DMA IRQ Channel deactivation */ + HAL_NVIC_DisableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ); + + if(hsai->Instance == AUDIO_OUT_SAIx) + { + /* Deinitialize the DMA stream */ + HAL_DMA_DeInit(hsai->hdmatx); + } + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(hsai); + + /* Deactivates CODEC_SAI pins FS, SCK, MCK and SD by putting them in input mode */ + gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN | AUDIO_OUT_SAIx_SCK_PIN | AUDIO_OUT_SAIx_SD_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN; + HAL_GPIO_DeInit(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, gpio_init_structure.Pin); + + /* Disable SAI clock */ + AUDIO_OUT_SAIx_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the applic + by surcharging this __weak function */ +} + +/** + * @brief Clock Config. + * @param hsai: might be required to set audio peripheral predivider if any. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @param Params + * @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params) +{ + RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; + + HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); + + /* Set the PLL configuration according to the audio frequency */ + if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) + { + /* Configure PLLSAI prescalers */ + /* PLLSAI_VCO: VCO_429M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 429/2 = 214.5 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 214.5/19 = 11.289 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI1; + rcc_ex_clk_init_struct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 429; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 2; + rcc_ex_clk_init_struct.PLLI2SDivQ = 19; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + + } + else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */ + { + /* SAI clock config + PLLSAI_VCO: VCO_344M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 344/7 = 49.142 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 49.142/1 = 49.142 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI1; + rcc_ex_clk_init_struct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 344; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 7; + rcc_ex_clk_init_struct.PLLI2SDivQ = 1; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + } +} + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Initializes the Audio Codec audio interface (SAI). + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @note The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123 + * and user can update this configuration using + * @retval None + */ +static void SAIx_Out_Init(uint32_t AudioFreq) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_out_sai.Init.MonoStereoMode = SAI_STEREOMODE; + haudio_out_sai.Init.AudioFrequency = AudioFreq; + haudio_out_sai.Init.AudioMode = SAI_MODEMASTER_TX; + haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLED; + haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; + haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; + haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLED; + haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + haudio_out_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; + haudio_out_sai.Init.CompandingMode = SAI_NOCOMPANDING; + haudio_out_sai.Init.TriState = SAI_OUTPUT_NOTRELEASED; + haudio_out_sai.Init.Mckdiv = 0; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_out_sai.FrameInit.FrameLength = 128; + haudio_out_sai.FrameInit.ActiveFrameLength = 64; + haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot actives */ + haudio_out_sai.SlotInit.FirstBitOffset = 0; + haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_out_sai.SlotInit.SlotNumber = 4; + haudio_out_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_0123; + + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Deinitializes the Audio Codec audio interface (SAI). + * @retval None + */ +static void SAIx_Out_DeInit(void) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + HAL_SAI_DeInit(&haudio_out_sai); +} + +/** + * @brief Initializes the Audio Codec audio interface (SAI). + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @note The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123 + * and user can update this configuration using + * @retval None + */ +static void SAIx_In_Init(uint32_t AudioFreq) +{ + /* Initialize SAI1 block A in MASTER TX */ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_out_sai.Init.MonoStereoMode = SAI_STEREOMODE; + haudio_out_sai.Init.AudioFrequency = AudioFreq; + haudio_out_sai.Init.AudioMode = SAI_MODEMASTER_RX; + haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; + haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE; + haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; + haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE; + haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + haudio_out_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; + haudio_out_sai.Init.CompandingMode = SAI_NOCOMPANDING; + haudio_out_sai.Init.TriState = SAI_OUTPUT_NOTRELEASED; + haudio_out_sai.Init.Mckdiv = 0; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_out_sai.FrameInit.FrameLength = 64; + haudio_out_sai.FrameInit.ActiveFrameLength = 32; + haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot actives */ + haudio_out_sai.SlotInit.FirstBitOffset = 0; + haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_out_sai.SlotInit.SlotNumber = 4; + haudio_out_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_02; + + HAL_SAI_Init(&haudio_out_sai); + + /* Initialize SAI1 block B in SLAVE RX synchronous from SAI1 block A */ + /* Initialize the haudio_in_sai Instance parameter */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_in_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_in_sai.Init.MonoStereoMode = SAI_STEREOMODE; + haudio_in_sai.Init.AudioFrequency = AudioFreq; + haudio_in_sai.Init.AudioMode = SAI_MODESLAVE_RX; + haudio_in_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; + haudio_in_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_in_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_in_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_in_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; + haudio_in_sai.Init.Synchro = SAI_SYNCHRONOUS; + haudio_in_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; + haudio_in_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + haudio_in_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; + haudio_in_sai.Init.CompandingMode = SAI_NOCOMPANDING; + haudio_in_sai.Init.TriState = SAI_OUTPUT_RELEASED; + haudio_in_sai.Init.Mckdiv = 0; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_in_sai.FrameInit.FrameLength = 64; + haudio_in_sai.FrameInit.ActiveFrameLength = 32; + haudio_in_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_in_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_in_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot active */ + haudio_in_sai.SlotInit.FirstBitOffset = 0; + haudio_in_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_in_sai.SlotInit.SlotNumber = 4; + haudio_in_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_02; + + HAL_SAI_Init(&haudio_in_sai); + + /* Enable SAI peripheral */ + __HAL_SAI_ENABLE(&haudio_in_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Deinitializes the output Audio Codec audio interface (SAI). + * @retval None + */ +static void SAIx_In_DeInit(void) +{ + /* Initialize the haudio_in_sai Instance parameter */ + haudio_in_sai.Instance = AUDIO_IN_SAIx; + haudio_out_sai.Instance = AUDIO_OUT_SAIx; + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(&haudio_in_sai); + + HAL_SAI_DeInit(&haudio_in_sai); + HAL_SAI_DeInit(&haudio_out_sai); +} + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO_In_Private_Functions STM32F769I_DISCOVERY_AUDIO_In Private Functions + * @{ + */ + +/** + * @brief Initialize wave recording. + * @param AudioFreq: Audio frequency to be configured for the DFSDM peripheral. + * @param BitRes: Audio frequency to be configured for the DFSDM peripheral. + * @param ChnlNbr: Audio frequency to be configured for the DFSDM peripheral. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + return BSP_AUDIO_IN_InitEx(INPUT_DEVICE_DIGITAL_MIC, AudioFreq, BitRes, ChnlNbr); +} + +/** + * @brief Initialize wave recording. + * @param InputDevice: INPUT_DEVICE_DIGITAL_MIC or INPUT_DEVICE_ANALOG_MIC. + * @param AudioFreq: Audio frequency to be configured. + * @param BitRes: Audio bit resolution to be configured.. + * @param ChnlNbr: Number of channel to be configured. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + uint8_t ret = AUDIO_ERROR; + AudioIn_Device = InputDevice; + + if(InputDevice == INPUT_DEVICE_DIGITAL_MIC) + { + AudioIn_ChannelNumber = ChnlNbr; + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_IN_ClockConfig(&hAudioInTopLeftFilter, AudioFreq, NULL); + + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_IN_MspInit(); + + /* Initializes DFSDM peripheral */ + DFSDMx_Init(AudioFreq); + ret = AUDIO_OK; + } + else + { + /* Disable SAI */ + SAIx_In_DeInit(); + + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_in_sai, AudioFreq, NULL); + + haudio_in_sai.Instance = AUDIO_IN_SAIx; + if(HAL_SAI_GetState(&haudio_in_sai) == HAL_SAI_STATE_RESET) + { + BSP_AUDIO_OUT_MspInit(&haudio_in_sai, NULL); + BSP_AUDIO_IN_MspInit(); + } + + SAIx_In_Init(AudioFreq); + + if((wm8994_drv.ReadID(AUDIO_I2C_ADDRESS)) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, InputDevice, 100, AudioFreq); + } + } + + /* Return AUDIO_OK when all operations are correctly done */ + return ret; +} + +/** + * @brief Allocate channel buffer scratch + * @param pScratch : pointer to scratch tables. + * @param size of scratch buffer + */ +uint8_t BSP_AUDIO_IN_AllocScratch (int32_t *pScratch, uint32_t size) +{ + uint32_t idx; + + ScratchSize = (size / AudioIn_ChannelNumber); + + /* copy scratch pointers */ + for (idx = 0; idx < AudioIn_ChannelNumber; idx++) + { + pScratchBuff[idx] = (int32_t *)(pScratch + (idx * ScratchSize)); + } + /* Return AUDIO_OK */ + return AUDIO_OK; +} + +/** + * @brief Return audio in channel number + * @retval Number of channel + */ +uint8_t BSP_AUDIO_IN_GetChannelNumber(void) +{ + return AudioIn_ChannelNumber; +} + +/** + * @brief Start audio recording. + * @param pbuf: Main buffer pointer for the recorded data storing + * @param size: Current size of the recorded buffer + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size) +{ + if (AudioIn_Device == INPUT_DEVICE_DIGITAL_MIC) + { + hAudioIn.pRecBuf = pbuf; + hAudioIn.RecSize = size; + /* Reset Application Buffer Trigger */ + AppBuffTrigger = 0; + AppBuffHalf = 0; + + if(AudioIn_ChannelNumber > 2) + { + /* Call the Media layer start function for buttom right channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInButtomRightFilter, pScratchBuff[2], ScratchSize)) + { + return AUDIO_ERROR; + } + + /* Call the Media layer start function for buttom left channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInButtomLeftFilter, pScratchBuff[3], ScratchSize)) + { + return AUDIO_ERROR; + } + } + + /* Call the Media layer start function for top right channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInTopRightFilter, pScratchBuff[0], ScratchSize)) + { + return AUDIO_ERROR; + } + + /* Call the Media layer start function for top left channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInTopLeftFilter, pScratchBuff[1], ScratchSize)) + { + return AUDIO_ERROR; + } + } + else + { + /* Start the process receive DMA */ + if(HAL_OK !=HAL_SAI_Receive_DMA(&haudio_in_sai, (uint8_t*)pbuf, size)) + { + return AUDIO_ERROR; + } + } + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Stop audio recording. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Stop(void) +{ + if (AudioIn_Device == INPUT_DEVICE_DIGITAL_MIC) + { + AppBuffTrigger = 0; + AppBuffHalf = 0; + + if(AudioIn_ChannelNumber > 2) + { + /* Call the Media layer stop function for buttom right channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInButtomRightFilter)) + { + return AUDIO_ERROR; + } + + /* Call the Media layer stop function for buttom left channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInButtomLeftFilter)) + { + return AUDIO_ERROR; + } + } + + /* Call the Media layer stop function for top right channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInTopRightFilter)) + { + return AUDIO_ERROR; + } + + /* Call the Media layer stop function for top left channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInTopLeftFilter)) + { + return AUDIO_ERROR; + } + } + else + { + /* Call the Media layer stop function */ + HAL_SAI_DMAStop(&haudio_in_sai); + + /* Call Audio Codec Stop function */ + if(audio_drv->Stop(AUDIO_I2C_ADDRESS, CODEC_PDWN_HW) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Wait at least 100us */ + HAL_Delay(1); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } + } + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Pause the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Pause(void) +{ + if(AudioIn_ChannelNumber > 2) + { + /* Call the Media layer stop function */ + if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInButtomRightFilter)) + { + return AUDIO_ERROR; + } + + /* Call the Media layer stop function */ + if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInButtomLeftFilter)) + { + return AUDIO_ERROR; + } + } + /* Call the Media layer stop function */ + if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInTopRightFilter)) + { + return AUDIO_ERROR; + } + + /* Call the Media layer stop function */ + if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInTopLeftFilter)) + { + return AUDIO_ERROR; + } + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Resume the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Resume(void) +{ + if(AudioIn_ChannelNumber > 2) + { + /* Call the Media layer start function for buttom right channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInButtomRightFilter, pScratchBuff[2], ScratchSize)) + { + return AUDIO_ERROR; + } + + /* Call the Media layer start function for buttom left channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInButtomLeftFilter, pScratchBuff[3], ScratchSize)) + { + return AUDIO_ERROR; + } + } + /* Call the Media layer start function for top right channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInTopRightFilter, pScratchBuff[0], ScratchSize)) + { + return AUDIO_ERROR; + } + + /* Call the Media layer start function for top left channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInTopLeftFilter, pScratchBuff[1], ScratchSize)) + { + return AUDIO_ERROR; + } + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Deinit the audio IN peripherals. + * @retval None + */ +void BSP_AUDIO_IN_DeInit(void) +{ + BSP_AUDIO_IN_MspDeInit(); + + if(AudioIn_Device == INPUT_DEVICE_DIGITAL_MIC) + { + DFSDMx_DeInit(); + } + else + { + SAIx_In_DeInit(); + } +} + +/** + * @brief Regular conversion complete callback. + * @note In interrupt mode, user has to read conversion value in this function + using HAL_DFSDM_FilterGetRegularValue. + * @param hdfsdm_filter : DFSDM filter handle. + * @retval None + */ +void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter) +{ + uint32_t index = 0; + + if(hdfsdm_filter == &hAudioInTopLeftFilter) + { + DmaTopLeftRecCplt = 1; + } + else if(hdfsdm_filter == &hAudioInTopRightFilter) + { + DmaTopRightRecCplt = 1; + } + else if(hdfsdm_filter == &hAudioInButtomLeftFilter) + { + DmaButtomLeftRecCplt = 1; + } + else + { + DmaButtomRightRecCplt = 1; + } + + if(AudioIn_ChannelNumber > 2) + { + if((DmaTopLeftRecCplt == 1) && (DmaTopRightRecCplt == 1) && (DmaButtomLeftRecCplt == 1) && (DmaButtomRightRecCplt == 1)) + { + for(index = (ScratchSize/2) ; index < ScratchSize; index++) + { + hAudioIn.pRecBuf[AppBuffTrigger] = (uint16_t)(SaturaLH((pScratchBuff[1][index] >> 8), -32760, 32760)); + hAudioIn.pRecBuf[AppBuffTrigger + 1] = (uint16_t)(SaturaLH((pScratchBuff[0][index] >> 8), -32760, 32760)); + hAudioIn.pRecBuf[AppBuffTrigger + 2] = (uint16_t)(SaturaLH((pScratchBuff[3][index] >> 8), -32760, 32760)); + hAudioIn.pRecBuf[AppBuffTrigger + 3] = (uint16_t)(SaturaLH((pScratchBuff[2][index] >> 8), -32760, 32760)); + AppBuffTrigger +=4; + } + DmaTopLeftRecCplt = 0; + DmaTopRightRecCplt = 0; + DmaButtomLeftRecCplt = 0; + DmaButtomRightRecCplt = 0; + } + } + else + { + if((DmaTopLeftRecCplt == 1) && (DmaTopRightRecCplt == 1)) + { + for(index = (ScratchSize/2) ; index < ScratchSize; index++) + { + hAudioIn.pRecBuf[AppBuffTrigger] = (uint16_t)(SaturaLH((pScratchBuff[1][index] >> 8), -32760, 32760)); + hAudioIn.pRecBuf[AppBuffTrigger + 1] = (uint16_t)(SaturaLH((pScratchBuff[0][index] >> 8), -32760, 32760)); + AppBuffTrigger +=2; + } + DmaTopLeftRecCplt = 0; + DmaTopRightRecCplt = 0; + } + } + + /* Call Half Transfer Complete callback */ + if((AppBuffTrigger == hAudioIn.RecSize/2) && (AppBuffHalf == 0)) + { + AppBuffHalf = 1; + BSP_AUDIO_IN_HalfTransfer_CallBack(); + } + /* Call Transfer Complete callback */ + if(AppBuffTrigger == hAudioIn.RecSize) + { + /* Reset Application Buffer Trigger */ + AppBuffTrigger = 0; + AppBuffHalf = 0; + /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ + BSP_AUDIO_IN_TransferComplete_CallBack(); + } +} + +/** + * @brief Half regular conversion complete callback. + * @param hdfsdm_filter : DFSDM filter handle. + * @retval None + */ +void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter) +{ + uint32_t index = 0; + + if(hdfsdm_filter == &hAudioInTopLeftFilter) + { + DmaTopLeftRecHalfCplt = 1; + } + else if(hdfsdm_filter == &hAudioInTopRightFilter) + { + DmaTopRightRecHalfCplt = 1; + } + else if(hdfsdm_filter == &hAudioInButtomLeftFilter) + { + DmaButtomLeftRecHalfCplt = 1; + } + else + { + DmaButtomRightRecHalfCplt = 1; + } + + if(AudioIn_ChannelNumber > 2) + { + if((DmaTopLeftRecHalfCplt == 1) && (DmaTopRightRecHalfCplt == 1) && (DmaButtomLeftRecHalfCplt == 1) && (DmaButtomRightRecHalfCplt == 1)) + { + for(index = 0 ; index < ScratchSize/2; index++) + { + hAudioIn.pRecBuf[AppBuffTrigger] = (uint16_t)(SaturaLH((pScratchBuff[1][index] >> 8), -32760, 32760)); + hAudioIn.pRecBuf[AppBuffTrigger + 1] = (uint16_t)(SaturaLH((pScratchBuff[0][index] >> 8), -32760, 32760)); + hAudioIn.pRecBuf[AppBuffTrigger + 2] = (uint16_t)(SaturaLH((pScratchBuff[3][index] >> 8), -32760, 32760)); + hAudioIn.pRecBuf[AppBuffTrigger + 3] = (uint16_t)(SaturaLH((pScratchBuff[2][index] >> 8), -32760, 32760)); + AppBuffTrigger +=4; + } + DmaTopLeftRecHalfCplt = 0; + DmaTopRightRecHalfCplt = 0; + DmaButtomLeftRecHalfCplt = 0; + DmaButtomRightRecHalfCplt = 0; + } + } + else + { + if((DmaTopLeftRecHalfCplt == 1) && (DmaTopRightRecHalfCplt == 1)) + { + for(index = 0 ; index < ScratchSize/2; index++) + { + hAudioIn.pRecBuf[AppBuffTrigger] = (uint16_t)(SaturaLH((pScratchBuff[1][index] >> 8), -32760, 32760)); + hAudioIn.pRecBuf[AppBuffTrigger + 1] = (uint16_t)(SaturaLH((pScratchBuff[0][index] >> 8), -32760, 32760)); + AppBuffTrigger +=2; + } + DmaTopLeftRecHalfCplt = 0; + DmaTopRightRecHalfCplt = 0; + } + } + + /* Call Half Transfer Complete callback */ + if((AppBuffTrigger == hAudioIn.RecSize/2) && (AppBuffHalf == 0)) + { + AppBuffHalf = 1; + BSP_AUDIO_IN_HalfTransfer_CallBack(); + } + /* Call Transfer Complete callback */ + if(AppBuffTrigger == hAudioIn.RecSize) + { + /* Reset Application Buffer Trigger */ + AppBuffTrigger = 0; + AppBuffHalf = 0; + /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ + BSP_AUDIO_IN_TransferComplete_CallBack(); + } +} + +/** + * @brief Half reception complete callback. + * @param hsai : SAI handle. + * @retval None + */ +void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32769i_discovery_audio.h) */ + BSP_AUDIO_IN_HalfTransfer_CallBack(); +} + +/** + * @brief Reception complete callback. + * @param hsai : SAI handle. + * @retval None + */ +void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ + BSP_AUDIO_IN_TransferComplete_CallBack(); +} + +/** + * @brief User callback when record buffer is filled. + * @retval None + */ +__weak void BSP_AUDIO_IN_TransferComplete_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Audio IN Error callback function. + * @retval None + */ +__weak void BSP_AUDIO_IN_Error_CallBack(void) +{ + /* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +} + +/** + * @brief Initialize BSP_AUDIO_IN MSP. + * @retval None + */ +__weak void BSP_AUDIO_IN_MspInit(void) +{ + if (AudioIn_Device == INPUT_DEVICE_DIGITAL_MIC) + { + /* MSP channels initialization */ + DFSDMx_ChannelMspInit(); + /* MSP filters initialization */ + DFSDMx_FilterMspInit(); + } + else + { + SAI_AUDIO_IN_MspInit(&haudio_in_sai, NULL); + } +} + +/** + * @brief DeInitialize BSP_AUDIO_IN MSP. + * @retval None + */ +__weak void BSP_AUDIO_IN_MspDeInit(void) +{ + if (AudioIn_Device == INPUT_DEVICE_DIGITAL_MIC) + { + /* MSP channels initialization */ + DFSDMx_ChannelMspDeInit(); + /* MSP filters initialization */ + DFSDMx_FilterMspDeInit(); + } + else + { + SAI_AUDIO_IN_MspDeInit(&haudio_in_sai, NULL); + } +} + +/** + * @brief Clock Config. + * @param hdfsdm_filter: might be required to set audio peripheral predivider if any. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @param Params + * @note This API is called by BSP_AUDIO_IN_Init() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_AUDIO_IN_ClockConfig(DFSDM_Filter_HandleTypeDef *hdfsdm_filter, uint32_t AudioFreq, void *Params) +{ + RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; + + HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); + + /* Set the PLL configuration according to the audio frequency */ + if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) + { + /* Configure PLLSAI prescalers */ + /* PLLI2S_VCO: VCO_429M + SAI_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 429/2 = 214.5 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ = 214.5/19 = 11.289 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 429; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 2; + rcc_ex_clk_init_struct.PLLI2SDivQ = 19; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + + } + else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_32K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */ + { + /* SAI clock config + PLLI2S_VCO: VCO_344M + SAI_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 344/7 = 49.142 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ = 49.142/1 = 49.142 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 344; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 7; + rcc_ex_clk_init_struct.PLLI2SDivQ = 1; + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + } + + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_DFSDM1_AUDIO; + rcc_ex_clk_init_struct.Dfsdm1AudioClockSelection = RCC_DFSDM1AUDIOCLKSOURCE_SAI2; + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); +} + +/******************************************************************************* + Static Functions +*******************************************************************************/ +/** + * @brief Initialize the Digital Filter for Sigma-Delta Modulators interface (DFSDM). + * @param AudioFreq: Audio frequency to be used to set correctly the DFSDM peripheral. + * @note Channel output Clock Divider and Filter Oversampling are calculated as follow: + * - Clock_Divider = CLK(input DFSDM)/CLK(micro) with + * 1MHZ < CLK(micro) < 3.2MHZ (TYP 2.4MHZ for MP34DT01TR) + * - Oversampling = CLK(input DFSDM)/(Clock_Divider * AudioFreq) + * @retval AUDIO_OK if correct communication, else wrong communication + */ +static uint8_t DFSDMx_Init(uint32_t AudioFreq) +{ + /****************************************************************************/ + /********************** Channels configuration *****************************/ + /****************************************************************************/ + /* CHANNEL 1 configuration */ + __HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(&hAudioInTopLeftChannel); + hAudioInTopLeftChannel.Instance = DFSDM1_Channel1; + hAudioInTopLeftChannel.Init.OutputClock.Activation = ENABLE; + hAudioInTopLeftChannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO; + /* Set the DFSDM clock OUT audio frequency configuration */ + hAudioInTopLeftChannel.Init.OutputClock.Divider = DFSDM_CLOCK_DIVIDER(AudioFreq); + hAudioInTopLeftChannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS; + hAudioInTopLeftChannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE; + hAudioInTopLeftChannel.Init.Input.Pins = DFSDM_CHANNEL_SAME_CHANNEL_PINS; + /* Request to sample stable data for LEFT micro on Rising edge */ + hAudioInTopLeftChannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_RISING; + hAudioInTopLeftChannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL; + hAudioInTopLeftChannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_FASTSINC_ORDER; + hAudioInTopLeftChannel.Init.Awd.Oversampling = 10; + hAudioInTopLeftChannel.Init.Offset = 0; + hAudioInTopLeftChannel.Init.RightBitShift = DFSDM_RIGHT_BIT_SHIFT(AudioFreq); + if(HAL_OK != HAL_DFSDM_ChannelInit(&hAudioInTopLeftChannel)) + { + return AUDIO_ERROR; + } + + /* CHANNEL 0 configuration */ + __HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(&hAudioInTopRightChannel); + hAudioInTopRightChannel.Instance = DFSDM1_Channel0; + hAudioInTopRightChannel.Init.OutputClock.Activation = ENABLE; + hAudioInTopRightChannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO; + /* Set the DFSDM clock OUT audio frequency configuration */ + hAudioInTopRightChannel.Init.OutputClock.Divider = DFSDM_CLOCK_DIVIDER(AudioFreq); + hAudioInTopRightChannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS; + hAudioInTopRightChannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE; + hAudioInTopRightChannel.Init.Input.Pins = DFSDM_CHANNEL_FOLLOWING_CHANNEL_PINS; + /* Request to sample stable data for RIGHT micro on Falling edge */ + hAudioInTopRightChannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_FALLING; + hAudioInTopRightChannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL; + hAudioInTopRightChannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_FASTSINC_ORDER; + hAudioInTopRightChannel.Init.Awd.Oversampling = 10; + hAudioInTopRightChannel.Init.Offset = 0; + hAudioInTopRightChannel.Init.RightBitShift = DFSDM_RIGHT_BIT_SHIFT(AudioFreq); + if(HAL_OK != HAL_DFSDM_ChannelInit(&hAudioInTopRightChannel)) + { + return AUDIO_ERROR; + } + + if(AudioIn_ChannelNumber > 2) + { + /* CHANNEL 5 configuration */ + __HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(&hAudioInButtomLeftChannel); + hAudioInButtomLeftChannel.Instance = DFSDM1_Channel5; + hAudioInButtomLeftChannel.Init.OutputClock.Activation = ENABLE; + hAudioInButtomLeftChannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO; + /* Set the DFSDM clock OUT audio frequency configuration */ + hAudioInButtomLeftChannel.Init.OutputClock.Divider = DFSDM_CLOCK_DIVIDER(AudioFreq); + hAudioInButtomLeftChannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS; + hAudioInButtomLeftChannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE; + hAudioInButtomLeftChannel.Init.Input.Pins = DFSDM_CHANNEL_SAME_CHANNEL_PINS; + /* Request to sample stable data for LEFT micro on Rising edge */ + hAudioInButtomLeftChannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_RISING; + hAudioInButtomLeftChannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL; + hAudioInButtomLeftChannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_FASTSINC_ORDER; + hAudioInButtomLeftChannel.Init.Awd.Oversampling = 10; + hAudioInButtomLeftChannel.Init.Offset = 0; + hAudioInButtomLeftChannel.Init.RightBitShift = DFSDM_RIGHT_BIT_SHIFT(AudioFreq); + if(HAL_OK != HAL_DFSDM_ChannelInit(&hAudioInButtomLeftChannel)) + { + return AUDIO_ERROR; + } + + /* CHANNEL 4 configuration */ + __HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(&hAudioInButtomRightChannel); + hAudioInButtomRightChannel.Instance = DFSDM1_Channel4; + hAudioInButtomRightChannel.Init.OutputClock.Activation = ENABLE; + hAudioInButtomRightChannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO; + /* Set the DFSDM clock OUT audio frequency configuration */ + hAudioInButtomRightChannel.Init.OutputClock.Divider = DFSDM_CLOCK_DIVIDER(AudioFreq); + hAudioInButtomRightChannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS; + hAudioInButtomRightChannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE; + hAudioInButtomRightChannel.Init.Input.Pins = DFSDM_CHANNEL_FOLLOWING_CHANNEL_PINS; + /* Request to sample stable data for RIGHT micro on Falling edge */ + hAudioInButtomRightChannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_FALLING; + hAudioInButtomRightChannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL; + hAudioInButtomRightChannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_FASTSINC_ORDER; + hAudioInButtomRightChannel.Init.Awd.Oversampling = 10; + hAudioInButtomRightChannel.Init.Offset = 0; + hAudioInButtomRightChannel.Init.RightBitShift = DFSDM_RIGHT_BIT_SHIFT(AudioFreq); + if(HAL_OK != HAL_DFSDM_ChannelInit(&hAudioInButtomRightChannel)) + { + return AUDIO_ERROR; + } + } + /****************************************************************************/ + /********************** Filters configuration ******************************/ + /****************************************************************************/ + + /* FILTER 0 configuration */ + __HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&hAudioInTopLeftFilter); + hAudioInTopLeftFilter.Instance = AUDIO_DFSDMx_TOP_LEFT_FILTER; + hAudioInTopLeftFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SW_TRIGGER; + hAudioInTopLeftFilter.Init.RegularParam.FastMode = ENABLE; + hAudioInTopLeftFilter.Init.RegularParam.DmaMode = ENABLE; + hAudioInTopLeftFilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER; + hAudioInTopLeftFilter.Init.InjectedParam.ScanMode = ENABLE; + hAudioInTopLeftFilter.Init.InjectedParam.DmaMode = DISABLE; + hAudioInTopLeftFilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM1_TRGO; + hAudioInTopLeftFilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_RISING_EDGE; + hAudioInTopLeftFilter.Init.FilterParam.SincOrder = DFSDM_FILTER_ORDER(AudioFreq); + /* Set the DFSDM Filters Oversampling to have correct sample rate */ + hAudioInTopLeftFilter.Init.FilterParam.Oversampling = DFSDM_OVER_SAMPLING(AudioFreq); + hAudioInTopLeftFilter.Init.FilterParam.IntOversampling = 1; + if(HAL_OK != HAL_DFSDM_FilterInit(&hAudioInTopLeftFilter)) + { + return AUDIO_ERROR; + } + + /* Configure injected channel */ + if(HAL_OK != HAL_DFSDM_FilterConfigRegChannel(&hAudioInTopLeftFilter, AUDIO_DFSDMx_TOP_LEFT_CHANNEL, DFSDM_CONTINUOUS_CONV_ON)) + { + return AUDIO_ERROR; + } + + /* FILTER 1 configuration */ + __HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&hAudioInTopRightFilter); + hAudioInTopRightFilter.Instance = AUDIO_DFSDMx_TOP_RIGHT_FILTER; + hAudioInTopRightFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SYNC_TRIGGER; + hAudioInTopRightFilter.Init.RegularParam.FastMode = ENABLE; + hAudioInTopRightFilter.Init.RegularParam.DmaMode = ENABLE; + hAudioInTopRightFilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER; + hAudioInTopRightFilter.Init.InjectedParam.ScanMode = DISABLE; + hAudioInTopRightFilter.Init.InjectedParam.DmaMode = DISABLE; + hAudioInTopRightFilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM1_TRGO; + hAudioInTopRightFilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_RISING_EDGE; + hAudioInTopRightFilter.Init.FilterParam.SincOrder = DFSDM_FILTER_ORDER(AudioFreq); + /* Set the DFSDM Filters Oversampling to have correct sample rate */ + hAudioInTopRightFilter.Init.FilterParam.Oversampling = DFSDM_OVER_SAMPLING(AudioFreq); + hAudioInTopRightFilter.Init.FilterParam.IntOversampling = 1; + if(HAL_OK != HAL_DFSDM_FilterInit(&hAudioInTopRightFilter)) + { + return AUDIO_ERROR; + } + /* Configure injected channel */ + if(HAL_OK != HAL_DFSDM_FilterConfigRegChannel(&hAudioInTopRightFilter, AUDIO_DFSDMx_TOP_RIGHT_CHANNEL, DFSDM_CONTINUOUS_CONV_ON)) + { + return AUDIO_ERROR; + } + + if(AudioIn_ChannelNumber > 2) + { + /* FILTER 2 configuration */ + __HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&hAudioInButtomLeftFilter); + hAudioInButtomLeftFilter.Instance = AUDIO_DFSDMx_BUTTOM_LEFT_FILTER; + hAudioInButtomLeftFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SYNC_TRIGGER; + hAudioInButtomLeftFilter.Init.RegularParam.FastMode = ENABLE; + hAudioInButtomLeftFilter.Init.RegularParam.DmaMode = ENABLE; + hAudioInButtomLeftFilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER; + hAudioInButtomLeftFilter.Init.InjectedParam.ScanMode = ENABLE; + hAudioInButtomLeftFilter.Init.InjectedParam.DmaMode = DISABLE; + hAudioInButtomLeftFilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM1_TRGO; + hAudioInButtomLeftFilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_RISING_EDGE; + hAudioInButtomLeftFilter.Init.FilterParam.SincOrder = DFSDM_FILTER_ORDER(AudioFreq); + /* Set the DFSDM Filters Oversampling to have correct sample rate */ + hAudioInButtomLeftFilter.Init.FilterParam.Oversampling = DFSDM_OVER_SAMPLING(AudioFreq); + hAudioInButtomLeftFilter.Init.FilterParam.IntOversampling = 1; + if(HAL_OK != HAL_DFSDM_FilterInit(&hAudioInButtomLeftFilter)) + { + return AUDIO_ERROR; + } + + /* Configure injected channel */ + if(HAL_OK != HAL_DFSDM_FilterConfigRegChannel(&hAudioInButtomLeftFilter, AUDIO_DFSDMx_BUTTOM_LEFT_CHANNEL, DFSDM_CONTINUOUS_CONV_ON)) + { + return AUDIO_ERROR; + } + + /* FILTER 3 configuration */ + __HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&hAudioInButtomRightFilter); + hAudioInButtomRightFilter.Instance = AUDIO_DFSDMx_BUTTOM_RIGHT_FILTER; + hAudioInButtomRightFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SYNC_TRIGGER; + hAudioInButtomRightFilter.Init.RegularParam.FastMode = ENABLE; + hAudioInButtomRightFilter.Init.RegularParam.DmaMode = ENABLE; + hAudioInButtomRightFilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER; + hAudioInButtomRightFilter.Init.InjectedParam.ScanMode = DISABLE; + hAudioInButtomRightFilter.Init.InjectedParam.DmaMode = DISABLE; + hAudioInButtomRightFilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM1_TRGO; + hAudioInButtomRightFilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_RISING_EDGE; + hAudioInButtomRightFilter.Init.FilterParam.SincOrder = DFSDM_FILTER_ORDER(AudioFreq); + /* Set the DFSDM Filters Oversampling to have correct sample rate */ + hAudioInButtomRightFilter.Init.FilterParam.Oversampling = DFSDM_OVER_SAMPLING(AudioFreq); + hAudioInButtomRightFilter.Init.FilterParam.IntOversampling = 1; + if(HAL_OK != HAL_DFSDM_FilterInit(&hAudioInButtomRightFilter)) + { + return AUDIO_ERROR; + } + /* Configure injected channel */ + if(HAL_OK != HAL_DFSDM_FilterConfigRegChannel(&hAudioInButtomRightFilter, AUDIO_DFSDMx_BUTTOM_RIGHT_CHANNEL, DFSDM_CONTINUOUS_CONV_ON)) + { + return AUDIO_ERROR; + } + } + return AUDIO_OK; +} + +/** + * @brief De-initialize the Digital Filter for Sigma-Delta Modulators interface (DFSDM). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +static uint8_t DFSDMx_DeInit(void) +{ + /* De-initializes the DFSDM filters to allow access to DFSDM internal registers */ + if(HAL_OK != HAL_DFSDM_FilterDeInit(&hAudioInTopLeftFilter)) + { + return AUDIO_ERROR; + } + + if(HAL_OK != HAL_DFSDM_FilterDeInit(&hAudioInTopRightFilter)) + { + return AUDIO_ERROR; + } + + /* De-initializes the DFSDM channels to allow access to DFSDM internal registers */ + if(HAL_OK != HAL_DFSDM_ChannelDeInit(&hAudioInTopLeftChannel)) + { + return AUDIO_ERROR; + } + + if(HAL_OK != HAL_DFSDM_ChannelDeInit(&hAudioInTopRightChannel)) + { + return AUDIO_ERROR; + } + + if(AudioIn_ChannelNumber > 2) + { + /* De-initializes the DFSDM filters to allow access to DFSDM internal registers */ + if(HAL_OK != HAL_DFSDM_FilterDeInit(&hAudioInButtomLeftFilter)) + { + return AUDIO_ERROR; + } + + if(HAL_OK != HAL_DFSDM_FilterDeInit(&hAudioInButtomRightFilter)) + { + return AUDIO_ERROR; + } + + /* De-initializes the DFSDM channels to allow access to DFSDM internal registers */ + if(HAL_OK != HAL_DFSDM_ChannelDeInit(&hAudioInButtomLeftChannel)) + { + return AUDIO_ERROR; + } + + if(HAL_OK != HAL_DFSDM_ChannelDeInit(&hAudioInButtomRightChannel)) + { + return AUDIO_ERROR; + } + } + + return AUDIO_OK; +} + +/** + * @brief Initialize the DFSDM channel MSP. + * @retval None + */ +static void DFSDMx_ChannelMspInit(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /* Enable DFSDM clock */ + AUDIO_DFSDMx_CLK_ENABLE(); + + /* Enable GPIO clock */ + AUDIO_DFSDMx_DMIC_DATIN_GPIO_CLK_ENABLE(); + AUDIO_DFSDMx_CKOUT_DMIC_GPIO_CLK_ENABLE(); + + /* DFSDM pins configuration: DFSDM_CKOUT, DMIC_DATIN1 pins ------------------*/ + GPIO_InitStruct.Pin = AUDIO_DFSDMx_CKOUT_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = AUDIO_DFSDMx_CKOUT_AF; + HAL_GPIO_Init(AUDIO_DFSDMx_CKOUT_DMIC_GPIO_PORT, &GPIO_InitStruct); + + /* DFSDM pin configuration: DMIC_DATIN1 pin --------------------------------*/ + GPIO_InitStruct.Pin = AUDIO_DFSDMx_DMIC_DATIN1_PIN; + GPIO_InitStruct.Alternate = AUDIO_DFSDMx_DMIC_DATIN_AF; + HAL_GPIO_Init(AUDIO_DFSDMx_DMIC_DATIN_GPIO_PORT, &GPIO_InitStruct); + + if(AudioIn_ChannelNumber > 2) + { + /* DFSDM pin configuration: DMIC_DATIN5 pin --------------------------------*/ + GPIO_InitStruct.Pin = AUDIO_DFSDMx_DMIC_DATIN5_PIN; + GPIO_InitStruct.Alternate = AUDIO_DFSDMx_DMIC_DATIN_AF; + HAL_GPIO_Init(AUDIO_DFSDMx_DMIC_DATIN_GPIO_PORT, &GPIO_InitStruct); + } +} + +/** + * @brief DeInitialize the DFSDM channel MSP. + * @retval None + */ +static void DFSDMx_ChannelMspDeInit(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /* DFSDM pin configuration: DMIC_DATIN1 pin --------------------------------*/ + GPIO_InitStruct.Pin = AUDIO_DFSDMx_CKOUT_PIN; + HAL_GPIO_DeInit(AUDIO_DFSDMx_CKOUT_DMIC_GPIO_PORT, GPIO_InitStruct.Pin); + GPIO_InitStruct.Pin = AUDIO_DFSDMx_DMIC_DATIN1_PIN; + HAL_GPIO_DeInit(AUDIO_DFSDMx_DMIC_DATIN_GPIO_PORT, GPIO_InitStruct.Pin); + + if(AudioIn_ChannelNumber > 2) + { + /* DFSDM pin configuration: DMIC_DATIN5 pin ------------------------------*/ + GPIO_InitStruct.Pin = AUDIO_DFSDMx_CKOUT_PIN; + HAL_GPIO_DeInit(AUDIO_DFSDMx_CKOUT_DMIC_GPIO_PORT, GPIO_InitStruct.Pin); + GPIO_InitStruct.Pin = AUDIO_DFSDMx_DMIC_DATIN5_PIN; + HAL_GPIO_DeInit(AUDIO_DFSDMx_DMIC_DATIN_GPIO_PORT, GPIO_InitStruct.Pin); + } +} + +/** + * @brief Initialize the DFSDM filter MSP. + * @retval None + */ +static void DFSDMx_FilterMspInit(void) +{ + /* Enable DFSDM clock */ + AUDIO_DFSDMx_CLK_ENABLE(); + + /* Enable the DMA clock */ + AUDIO_DFSDMx_DMAx_CLK_ENABLE(); + + /*********** Configure DMA stream for TOP LEFT microphone *******************/ + hDmaTopLeft.Init.Direction = DMA_PERIPH_TO_MEMORY; + hDmaTopLeft.Init.PeriphInc = DMA_PINC_DISABLE; + hDmaTopLeft.Init.MemInc = DMA_MINC_ENABLE; + hDmaTopLeft.Init.PeriphDataAlignment = AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE; + hDmaTopLeft.Init.MemDataAlignment = AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE; + hDmaTopLeft.Init.Mode = DMA_CIRCULAR; + hDmaTopLeft.Init.Priority = DMA_PRIORITY_HIGH; + hDmaTopLeft.Instance = AUDIO_DFSDMx_DMAx_TOP_LEFT_STREAM; + hDmaTopLeft.Init.Channel = AUDIO_DFSDMx_DMAx_CHANNEL; + + /* Associate the DMA handle */ + __HAL_LINKDMA(&hAudioInTopLeftFilter, hdmaReg, hDmaTopLeft); + + /* Reset DMA handle state */ + __HAL_DMA_RESET_HANDLE_STATE(&hDmaTopLeft); + + /* Configure the DMA Channel */ + HAL_DMA_Init(&hDmaTopLeft); + + /* DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_DFSDMx_DMAx_TOP_LEFT_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_DFSDMx_DMAx_TOP_LEFT_IRQ); + + + /*********** Configure DMA stream for TOP RIGHT microphone ******************/ + hDmaTopRight.Init.Direction = DMA_PERIPH_TO_MEMORY; + hDmaTopRight.Init.PeriphInc = DMA_PINC_DISABLE; + hDmaTopRight.Init.MemInc = DMA_MINC_ENABLE; + hDmaTopRight.Init.PeriphDataAlignment = AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE; + hDmaTopRight.Init.MemDataAlignment = AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE; + hDmaTopRight.Init.Mode = DMA_CIRCULAR; + hDmaTopRight.Init.Priority = DMA_PRIORITY_HIGH; + hDmaTopRight.Instance = AUDIO_DFSDMx_DMAx_TOP_RIGHT_STREAM; + hDmaTopRight.Init.Channel = AUDIO_DFSDMx_DMAx_CHANNEL; + + /* Associate the DMA handle */ + __HAL_LINKDMA(&hAudioInTopRightFilter, hdmaReg, hDmaTopRight); + + /* Reset DMA handle state */ + __HAL_DMA_RESET_HANDLE_STATE(&hDmaTopRight); + + /* Configure the DMA Channel */ + HAL_DMA_Init(&hDmaTopRight); + + /* DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_DFSDMx_DMAx_TOP_RIGHT_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_DFSDMx_DMAx_TOP_RIGHT_IRQ); + + if(AudioIn_ChannelNumber > 2) + { + /*********** Configure DMA stream for BUTTOM LEFT microphone ****************/ + hDmaButtomLeft.Init.Direction = DMA_PERIPH_TO_MEMORY; + hDmaButtomLeft.Init.PeriphInc = DMA_PINC_DISABLE; + hDmaButtomLeft.Init.MemInc = DMA_MINC_ENABLE; + hDmaButtomLeft.Init.PeriphDataAlignment = AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE; + hDmaButtomLeft.Init.MemDataAlignment = AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE; + hDmaButtomLeft.Init.Mode = DMA_CIRCULAR; + hDmaButtomLeft.Init.Priority = DMA_PRIORITY_HIGH; + hDmaButtomLeft.Instance = AUDIO_DFSDMx_DMAx_BUTTOM_LEFT_STREAM; + hDmaButtomLeft.Init.Channel = AUDIO_DFSDMx_DMAx_CHANNEL; + + /* Associate the DMA handle */ + __HAL_LINKDMA(&hAudioInButtomLeftFilter, hdmaReg, hDmaButtomLeft); + + /* Reset DMA handle state */ + __HAL_DMA_RESET_HANDLE_STATE(&hDmaButtomLeft); + + /* Configure the DMA Channel */ + HAL_DMA_Init(&hDmaButtomLeft); + + /* DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_DFSDMx_DMAx_BUTTOM_LEFT_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_DFSDMx_DMAx_BUTTOM_LEFT_IRQ); + + + /*********** Configure DMA stream for BUTTOM RIGHT microphone ***************/ + hDmaButtomRight.Init.Direction = DMA_PERIPH_TO_MEMORY; + hDmaButtomRight.Init.PeriphInc = DMA_PINC_DISABLE; + hDmaButtomRight.Init.MemInc = DMA_MINC_ENABLE; + hDmaButtomRight.Init.PeriphDataAlignment = AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE; + hDmaButtomRight.Init.MemDataAlignment = AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE; + hDmaButtomRight.Init.Mode = DMA_CIRCULAR; + hDmaButtomRight.Init.Priority = DMA_PRIORITY_HIGH; + hDmaButtomRight.Instance = AUDIO_DFSDMx_DMAx_BUTTOM_RIGHT_STREAM; + hDmaButtomRight.Init.Channel = AUDIO_DFSDMx_DMAx_CHANNEL; + + /* Associate the DMA handle */ + __HAL_LINKDMA(&hAudioInButtomRightFilter, hdmaReg, hDmaButtomRight); + + /* Reset DMA handle state */ + __HAL_DMA_RESET_HANDLE_STATE(&hDmaButtomRight); + + /* Configure the DMA Channel */ + HAL_DMA_Init(&hDmaButtomRight); + + /* DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_DFSDMx_DMAx_BUTTOM_RIGHT_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_DFSDMx_DMAx_BUTTOM_RIGHT_IRQ); + } +} + +/** + * @brief DeInitialize the DFSDM filter MSP. + * @retval None + */ +static void DFSDMx_FilterMspDeInit(void) +{ + /* Configure the DMA Channel */ + HAL_DMA_DeInit(&hDmaTopLeft); + HAL_DMA_DeInit(&hDmaTopRight); + if(AudioIn_ChannelNumber > 2) + { + HAL_DMA_DeInit(&hDmaButtomLeft); + HAL_DMA_DeInit(&hDmaButtomRight); + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_audio.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_audio.h new file mode 100644 index 00000000..39e54f9a --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_audio.h @@ -0,0 +1,342 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_audio.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_discovery_audio.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_DISCOVERY_AUDIO_H +#define __STM32F769I_DISCOVERY_AUDIO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include audio component Driver */ +#include "../Components/wm8994/wm8994.h" +#include "stm32f769i_discovery.h" +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO STM32F769I_DISCOVERY_AUDIO + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO_Exported_Types STM32F769I_DISCOVERY_AUDIO Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO_Exported_Constants STM32F769I_DISCOVERY_AUDIO Exported Constants + * @{ + */ + +/** @defgroup BSP_Audio_Sample_Rate BSP Audio Sample Rate + * @{ + */ +#define BSP_AUDIO_FREQUENCY_96K SAI_AUDIO_FREQUENCY_96K +#define BSP_AUDIO_FREQUENCY_48K SAI_AUDIO_FREQUENCY_48K +#define BSP_AUDIO_FREQUENCY_44K SAI_AUDIO_FREQUENCY_44K +#define BSP_AUDIO_FREQUENCY_32K SAI_AUDIO_FREQUENCY_32K +#define BSP_AUDIO_FREQUENCY_22K SAI_AUDIO_FREQUENCY_22K +#define BSP_AUDIO_FREQUENCY_16K SAI_AUDIO_FREQUENCY_16K +#define BSP_AUDIO_FREQUENCY_11K SAI_AUDIO_FREQUENCY_11K +#define BSP_AUDIO_FREQUENCY_8K SAI_AUDIO_FREQUENCY_8K +/** + * @} + */ + +/*------------------------------------------------------------------------------ + USER SAI defines parameters + -----------------------------------------------------------------------------*/ +/** CODEC_AudioFrame_SLOT_TDMMode In W8994 codec the Audio frame contains 4 slots : TDM Mode + * TDM format : + * +------------------|------------------|--------------------|-------------------+ + * | CODEC_SLOT0 Left | CODEC_SLOT1 Left | CODEC_SLOT0 Right | CODEC_SLOT1 Right | + * +------------------------------------------------------------------------------+ + */ +/* To have 2 separate audio stream in Both headphone and speaker the 4 slot must be activated */ +#define CODEC_AUDIOFRAME_SLOT_0123 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_2 | SAI_SLOTACTIVE_3 + +/* To have an audio stream in headphone only SAI Slot 0 and Slot 2 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_02 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_2 +/* To have an audio stream in speaker only SAI Slot 1 and Slot 3 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_13 SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_3 + + +/* SAI peripheral configuration defines */ +#define AUDIO_OUT_SAIx SAI1_Block_A +#define AUDIO_OUT_SAIx_CLK_ENABLE() __HAL_RCC_SAI1_CLK_ENABLE() +#define AUDIO_OUT_SAIx_CLK_DISABLE() __HAL_RCC_SAI1_CLK_DISABLE() +#define AUDIO_OUT_SAIx_AF GPIO_AF6_SAI1 + +#define AUDIO_OUT_SAIx_MCLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE() +#define AUDIO_OUT_SAIx_MCLK_GPIO_PORT GPIOG +#define AUDIO_OUT_SAIx_MCLK_PIN GPIO_PIN_7 +#define AUDIO_OUT_SAIx_SD_FS_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() +#define AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT GPIOE +#define AUDIO_OUT_SAIx_FS_PIN GPIO_PIN_4 +#define AUDIO_OUT_SAIx_SCK_PIN GPIO_PIN_5 +#define AUDIO_OUT_SAIx_SD_PIN GPIO_PIN_6 + +/* SAI DMA Stream definitions */ +#define AUDIO_OUT_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_OUT_SAIx_DMAx_STREAM DMA2_Stream1 +#define AUDIO_OUT_SAIx_DMAx_CHANNEL DMA_CHANNEL_0 +#define AUDIO_OUT_SAIx_DMAx_IRQ DMA2_Stream1_IRQn +#define AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD +#define AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD +#define DMA_MAX_SZE 0xFFFF + +#define AUDIO_OUT_SAIx_DMAx_IRQHandler DMA2_Stream1_IRQHandler + +/* Select the interrupt preemption priority and subpriority for the DMA interrupt */ +#define AUDIO_OUT_IRQ_PREPRIO ((uint32_t)0x0E) + +/*------------------------------------------------------------------------------ + AUDIO IN CONFIGURATION +------------------------------------------------------------------------------*/ +/* SAI peripheral configuration defines */ +#define AUDIO_IN_SAIx SAI1_Block_B +#define AUDIO_IN_SAIx_CLK_ENABLE() __HAL_RCC_SAI1_CLK_ENABLE() +#define AUDIO_IN_SAIx_CLK_DISABLE() __HAL_RCC_SAI1_CLK_DISABLE() +#define AUDIO_IN_SAIx_AF GPIO_AF6_SAI1 +#define AUDIO_IN_SAIx_SD_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() +#define AUDIO_IN_SAIx_SD_GPIO_PORT GPIOE +#define AUDIO_IN_SAIx_SD_PIN GPIO_PIN_3 + +/* SAI DMA Stream definitions */ +#define AUDIO_IN_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_IN_SAIx_DMAx_STREAM DMA2_Stream4 +#define AUDIO_IN_SAIx_DMAx_CHANNEL DMA_CHANNEL_1 +#define AUDIO_IN_SAIx_DMAx_IRQ DMA2_Stream4_IRQn +#define AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD +#define AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD + +#define AUDIO_IN_INT_GPIO_ENABLE() __HAL_RCC_GPIOJ_CLK_ENABLE() +#define AUDIO_IN_INT_GPIO_PORT GPIOJ +#define AUDIO_IN_INT_GPIO_PIN GPIO_PIN_12 +#define AUDIO_IN_INT_IRQ EXTI15_10_IRQn + +/* DFSDM Configuration defines */ +#define AUDIO_DFSDMx_TOP_RIGHT_CHANNEL DFSDM_CHANNEL_0 +#define AUDIO_DFSDMx_TOP_LEFT_CHANNEL DFSDM_CHANNEL_1 +#define AUDIO_DFSDMx_BUTTOM_RIGHT_CHANNEL DFSDM_CHANNEL_4 +#define AUDIO_DFSDMx_BUTTOM_LEFT_CHANNEL DFSDM_CHANNEL_5 + +#define AUDIO_DFSDMx_TOP_LEFT_FILTER DFSDM1_Filter0 +#define AUDIO_DFSDMx_TOP_RIGHT_FILTER DFSDM1_Filter1 +#define AUDIO_DFSDMx_BUTTOM_LEFT_FILTER DFSDM1_Filter2 +#define AUDIO_DFSDMx_BUTTOM_RIGHT_FILTER DFSDM1_Filter3 + +#define AUDIO_DFSDMx_CLK_ENABLE() __HAL_RCC_DFSDM1_CLK_ENABLE() +#define AUDIO_DFSDMx_CKOUT_PIN GPIO_PIN_3 +#define AUDIO_DFSDMx_CKOUT_DMIC_GPIO_PORT GPIOD +#define AUDIO_DFSDMx_CKOUT_DMIC_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() +#define AUDIO_DFSDMx_DMIC_DATIN1_PIN GPIO_PIN_3 +#define AUDIO_DFSDMx_DMIC_DATIN5_PIN GPIO_PIN_11 +#define AUDIO_DFSDMx_DMIC_DATIN_GPIO_PORT GPIOC +#define AUDIO_DFSDMx_DMIC_DATIN_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define AUDIO_DFSDMx_DMIC_DATIN_AF GPIO_AF3_DFSDM1 +#define AUDIO_DFSDMx_CKOUT_AF GPIO_AF3_DFSDM1 + +/* DFSDM DMA Right and Left channels definitions */ +#define AUDIO_DFSDMx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_DFSDMx_DMAx_CHANNEL DMA_CHANNEL_8 +#define AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_WORD +#define AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_WORD + +#define AUDIO_DFSDMx_DMAx_TOP_LEFT_STREAM DMA2_Stream0 +#define AUDIO_DFSDMx_DMAx_TOP_LEFT_IRQ DMA2_Stream0_IRQn +#define AUDIO_DFSDMx_DMAx_TOP_LEFT_IRQHandler DMA2_Stream0_IRQHandler + +#define AUDIO_DFSDMx_DMAx_TOP_RIGHT_STREAM DMA2_Stream5 +#define AUDIO_DFSDMx_DMAx_TOP_RIGHT_IRQ DMA2_Stream5_IRQn +#define AUDIO_DFSDMx_DMAx_TOP_RIGHT_IRQHandler DMA2_Stream5_IRQHandler + +#define AUDIO_DFSDMx_DMAx_BUTTOM_LEFT_STREAM DMA2_Stream6 +#define AUDIO_DFSDMx_DMAx_BUTTOM_LEFT_IRQ DMA2_Stream6_IRQn +#define AUDIO_DFSDMx_DMAx_BUTTOM_LEFT_IRQHandler DMA2_Stream6_IRQHandler + +#define AUDIO_DFSDMx_DMAx_BUTTOM_RIGHT_STREAM DMA2_Stream7 +#define AUDIO_DFSDMx_DMAx_BUTTOM_RIGHT_IRQ DMA2_Stream7_IRQn +#define AUDIO_DFSDMx_DMAx_BUTTOM_RIGHT_IRQHandler DMA2_Stream7_IRQHandler + +/* Select the interrupt preemption priority and subpriority for the DMA interrupt */ +#define AUDIO_IN_IRQ_PREPRIO ((uint32_t)0x0F) + + +/*------------------------------------------------------------------------------ + CONFIGURATION: Audio Driver Configuration parameters +------------------------------------------------------------------------------*/ + +#define AUDIODATA_SIZE 2 /* 16-bits audio data size */ + +/* Audio status definition */ +#define AUDIO_OK ((uint8_t)0) +#define AUDIO_ERROR ((uint8_t)1) +#define AUDIO_TIMEOUT ((uint8_t)2) + +/* Audio In default settings */ +#define DEFAULT_AUDIO_IN_FREQ BSP_AUDIO_FREQUENCY_16K +#define DEFAULT_AUDIO_IN_BIT_RESOLUTION ((uint8_t)16) +#define DEFAULT_AUDIO_IN_CHANNEL_NBR ((uint8_t)2) +#define DEFAULT_AUDIO_IN_VOLUME ((uint16_t)64) + +/*------------------------------------------------------------------------------ + OUTPUT DEVICES definition +------------------------------------------------------------------------------*/ +/* Alias on existing output devices to adapt for 2 headphones output */ +#define OUTPUT_DEVICE_HEADPHONE1 OUTPUT_DEVICE_HEADPHONE +#define OUTPUT_DEVICE_HEADPHONE2 OUTPUT_DEVICE_SPEAKER /* Headphone2 is connected to Speaker output of the wm8994 */ + +/*------------------------------------------------------------------------------ + INPUT DEVICES definition +------------------------------------------------------------------------------*/ +/* MP34DT01TR digital microphone on PCB top side */ +#define INPUT_DEVICE_DIGITAL_MIC ((uint16_t)0) +/* Analog microphone input from 3.5 audio jack connector */ +#define INPUT_DEVICE_ANALOG_MIC INPUT_DEVICE_INPUT_LINE_1 + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO_Exported_Macros STM32F769I_DISCOVERY_AUDIO Exported Macros + * @{ + */ +#define DMA_MAX(x) (((x) <= DMA_MAX_SZE)? (x):DMA_MAX_SZE) +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO_OUT_Exported_Functions STM32F769I_DISCOVERY_AUDIO_OUT Exported Functions + * @{ + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq); +void BSP_AUDIO_OUT_DeInit(void); +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size); +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size); +uint8_t BSP_AUDIO_OUT_Pause(void); +uint8_t BSP_AUDIO_OUT_Resume(void); +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option); +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume); +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq); +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot); +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd); +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output); + +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function is called when the requested data has been completely transferred.*/ +void BSP_AUDIO_OUT_TransferComplete_CallBack(void); + +/* This function is called when half of the requested buffer has been transferred. */ +void BSP_AUDIO_OUT_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_OUT_Error_CallBack(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params); +void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params); +void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_AUDIO_IN_Exported_Functions STM32F769I_DISCOVERY_AUDIO_IN Exported Functions + * @{ + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_AllocScratch (int32_t *pScratch, uint32_t size); +uint8_t BSP_AUDIO_IN_GetChannelNumber(void); +void BSP_AUDIO_IN_DeInit(void); +uint8_t BSP_AUDIO_IN_Record(uint16_t *pData, uint32_t Size); +uint8_t BSP_AUDIO_IN_Stop(void); +uint8_t BSP_AUDIO_IN_Pause(void); +uint8_t BSP_AUDIO_IN_Resume(void); + +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled to prepare the next + buffer pointer and its size. */ +void BSP_AUDIO_IN_TransferComplete_CallBack(void); +void BSP_AUDIO_IN_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_IN_Error_CallBack(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_IN_ClockConfig(DFSDM_Filter_HandleTypeDef *hdfsdm_filter, uint32_t AudioFreq, void *Params); +void BSP_AUDIO_IN_MspInit(void); +void BSP_AUDIO_IN_MspDeInit(void); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_DISCOVERY_AUDIO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_eeprom.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_eeprom.c new file mode 100644 index 00000000..220159e1 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_eeprom.c @@ -0,0 +1,476 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_eeprom.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage an I2C M24LR64 + * EEPROM memory. + @verbatim + To be able to use this driver, the switch EE_M24LR64 must be defined + in your toolchain compiler preprocessor + + =================================================================== + Notes: + - The I2C EEPROM memory (M24LR64) is available on separate daughter + board ANT7-M24LR-A, which is not provided with the STM32F769I_DISCOVERY + board. + To use this driver you have to connect the ANT7-M24LR-A to CN2 + connector of STM32F769I_DISCOVERY board. + =================================================================== + + It implements a high level communication layer for read and write + from/to this memory. The needed STM32F7xx hardware resources (I2C and + GPIO) are defined in stm32f769i_discovery.h file, and the initialization is + performed in EEPROM_IO_Init() function declared in stm32f769i_discovery.c + file. + You can easily tailor this driver to any other development board, + by just adapting the defines for hardware resources and + EEPROM_IO_Init() function. + + @note In this driver, basic read and write functions (BSP_EEPROM_ReadBuffer() + and BSP_EEPROM_WritePage()) use DMA mode to perform the data + transfer to/from EEPROM memory. + + @note Regarding BSP_EEPROM_WritePage(), it is an optimized function to perform + small write (less than 1 page) BUT the number of bytes (combined to write start address) must not + cross the EEPROM page boundary. This function can only writes into + the boundaries of an EEPROM page. + This function doesn't check on boundaries condition (in this driver + the function BSP_EEPROM_WriteBuffer() which calls BSP_EEPROM_WritePage() is + responsible of checking on Page boundaries). + + + +-----------------------------------------------------------------+ + | Pin assignment for M24LR64 EEPROM | + +---------------------------------------+-----------+-------------+ + | STM32F7xx I2C Pins | EEPROM | Pin | + +---------------------------------------+-----------+-------------+ + | . | E0(GND) | 1 (0V) | + | . | AC0 | 2 | + | . | AC1 | 3 | + | . | VSS | 4 (0V) | + | SDA | SDA | 5 | + | SCL | SCL | 6 | + | . | E1(GND) | 7 (0V) | + | . | VDD | 8 (3.3V) | + +---------------------------------------+-----------+-------------+ + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f769i_discovery.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_discovery_eeprom.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY_EEPROM STM32F769I_DISCOVERY EEPROM + * @brief This file includes the I2C EEPROM driver of STM32F769I-DISCOVERY board. + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_EEPROM_Private_Types EEPROM Private Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_EEPROM_Private_Defines EEPROM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_EEPROM_Private_Macros EEPROM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_EEPROM_Private_Variables EEPROM Private Variables + * @{ + */ +__IO uint16_t EEPROMAddress = 0; +__IO uint16_t EEPROMDataRead; +__IO uint8_t EEPROMDataWrite; +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_EEPROM_Private_Function_Prototypes EEPROM Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_EEPROM_Private_Functions EEPROM Private Functions + * @{ + */ + +/** + * @brief Initializes peripherals used by the I2C EEPROM driver. + * @note There are 2 different versions of M24LR64 (A01 & A02). + * Then try to connect on 1st one (EEPROM_I2C_ADDRESS_A01) + * and if problem, check the 2nd one (EEPROM_I2C_ADDRESS_A02) + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) + */ +uint32_t BSP_EEPROM_Init(void) +{ + /* I2C Initialization */ + EEPROM_IO_Init(); + + /* Select the EEPROM address for A01 and check if OK */ + EEPROMAddress = EEPROM_I2C_ADDRESS_A01; + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + /* Select the EEPROM address for A02 and check if OK */ + EEPROMAddress = EEPROM_I2C_ADDRESS_A02; + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + return EEPROM_FAIL; + } + } + return EEPROM_OK; +} + +/** + * @brief DeInitializes the EEPROM. + * @retval EEPROM state + */ +uint8_t BSP_EEPROM_DeInit(void) +{ + /* I2C won't be disabled because common to other functionalities */ + return EEPROM_OK; +} + +/** + * @brief Reads a block of data from the EEPROM. + * @param pBuffer: pointer to the buffer that receives the data read from + * the EEPROM. + * @param ReadAddr: EEPROM's internal address to start reading from. + * @param NumByteToRead: pointer to the variable holding number of bytes to + * be read from the EEPROM. + * + * @note The variable pointed by NumByteToRead is reset to 0 when all the + * data are read from the EEPROM. Application should monitor this + * variable in order know when the transfer is complete. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead) +{ + uint32_t buffersize = *NumByteToRead; + + /* Set the pointer to the Number of data to be read. This pointer will be used + by the DMA Transfer Completer interrupt Handler in order to reset the + variable to 0. User should check on this variable in order to know if the + DMA transfer has been complete or not. */ + EEPROMDataRead = *NumByteToRead; + + if(EEPROM_IO_ReadData(EEPROMAddress, ReadAddr, pBuffer, buffersize) != HAL_OK) + { + BSP_EEPROM_TIMEOUT_UserCallback(); + return EEPROM_FAIL; + } + + /* If all operations OK, return EEPROM_OK (0) */ + return EEPROM_OK; +} + +/** + * @brief Writes more than one byte to the EEPROM with a single WRITE cycle. + * + * @note The number of bytes (combined to write start address) must not + * cross the EEPROM page boundary. This function can only write into + * the boundaries of an EEPROM page. + * This function doesn't check on boundaries condition (in this driver + * the function BSP_EEPROM_WriteBuffer() which calls BSP_EEPROM_WritePage() is + * responsible of checking on Page boundaries). + * + * @param pBuffer: pointer to the buffer containing the data to be written to + * the EEPROM. + * @param WriteAddr: EEPROM's internal address to write to. + * @param NumByteToWrite: pointer to the variable holding number of bytes to + * be written into the EEPROM. + * + * @note The variable pointed by NumByteToWrite is reset to 0 when all the + * data are written to the EEPROM. Application should monitor this + * variable in order know when the transfer is complete. + * + * @note This function just configure the communication and enable the DMA + * channel to transfer data. Meanwhile, the user application may perform + * other tasks in parallel. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite) +{ + uint32_t buffersize = *NumByteToWrite; + uint32_t status = EEPROM_OK; + + /* Set the pointer to the Number of data to be written. This pointer will be used + by the DMA Transfer Completer interrupt Handler in order to reset the + variable to 0. User should check on this variable in order to know if the + DMA transfer has been complete or not. */ + EEPROMDataWrite = *NumByteToWrite; + + if(EEPROM_IO_WriteData(EEPROMAddress, WriteAddr, pBuffer, buffersize) != HAL_OK) + { + BSP_EEPROM_TIMEOUT_UserCallback(); + status = EEPROM_FAIL; + } + + if(BSP_EEPROM_WaitEepromStandbyState() != EEPROM_OK) + { + return EEPROM_FAIL; + } + + /* If all operations OK, return EEPROM_OK (0) */ + return status; +} + +/** + * @brief Writes buffer of data to the I2C EEPROM. + * @param pBuffer: pointer to the buffer containing the data to be written + * to the EEPROM. + * @param WriteAddr: EEPROM's internal address to write to. + * @param NumByteToWrite: number of bytes to write to the EEPROM. + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WriteBuffer(uint8_t *pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite) +{ + uint16_t numofpage = 0, numofsingle = 0, count = 0; + uint16_t addr = 0; + uint8_t dataindex = 0; + uint32_t status = EEPROM_OK; + + addr = WriteAddr % EEPROM_PAGESIZE; + count = EEPROM_PAGESIZE - addr; + numofpage = NumByteToWrite / EEPROM_PAGESIZE; + numofsingle = NumByteToWrite % EEPROM_PAGESIZE; + + /* If WriteAddr is EEPROM_PAGESIZE aligned */ + if(addr == 0) + { + /* If NumByteToWrite < EEPROM_PAGESIZE */ + if(numofpage == 0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + /* Start writing data */ + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + /* If NumByteToWrite > EEPROM_PAGESIZE */ + else + { + while(numofpage--) + { + /* Store the number of data to be written */ + dataindex = EEPROM_PAGESIZE; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + + WriteAddr += EEPROM_PAGESIZE; + pBuffer += EEPROM_PAGESIZE; + } + + if(numofsingle!=0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + } + /* If WriteAddr is not EEPROM_PAGESIZE aligned */ + else + { + /* If NumByteToWrite < EEPROM_PAGESIZE */ + if(numofpage== 0) + { + /* If the number of data to be written is more than the remaining space + in the current page: */ + if(NumByteToWrite > count) + { + /* Store the number of data to be written */ + dataindex = count; + /* Write the data contained in same page */ + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + + /* Store the number of data to be written */ + dataindex = (NumByteToWrite - count); + /* Write the remaining data in the following page */ + status = BSP_EEPROM_WritePage((uint8_t*)(pBuffer + count), (WriteAddr + count), (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + else + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + /* If NumByteToWrite > EEPROM_PAGESIZE */ + else + { + NumByteToWrite -= count; + numofpage = NumByteToWrite / EEPROM_PAGESIZE; + numofsingle = NumByteToWrite % EEPROM_PAGESIZE; + + if(count != 0) + { + /* Store the number of data to be written */ + dataindex = count; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + WriteAddr += count; + pBuffer += count; + } + + while(numofpage--) + { + /* Store the number of data to be written */ + dataindex = EEPROM_PAGESIZE; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + WriteAddr += EEPROM_PAGESIZE; + pBuffer += EEPROM_PAGESIZE; + } + if(numofsingle != 0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + } + + /* If all operations OK, return EEPROM_OK (0) */ + return EEPROM_OK; +} + +/** + * @brief Wait for EEPROM Standby state. + * + * @note This function allows to wait and check that EEPROM has finished the + * last operation. It is mostly used after Write operation: after receiving + * the buffer to be written, the EEPROM may need additional time to actually + * perform the write operation. During this time, it doesn't answer to + * I2C packets addressed to it. Once the write operation is complete + * the EEPROM responds to its address. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WaitEepromStandbyState(void) +{ + /* Check if the maximum allowed number of trials has bee reached */ + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + /* If the maximum number of trials has been reached, exit the function */ + BSP_EEPROM_TIMEOUT_UserCallback(); + return EEPROM_TIMEOUT; + } + return EEPROM_OK; +} + +/** + * @brief Basic management of the timeout situation. + * @retval None + */ +__weak void BSP_EEPROM_TIMEOUT_UserCallback(void) +{ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_eeprom.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_eeprom.h new file mode 100644 index 00000000..b3451aef --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_eeprom.h @@ -0,0 +1,138 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_eeprom.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for + * the stm32f769i_discovery_eeprom.c firmware driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_DISCOVERY_EEPROM_H +#define __STM32F769I_DISCOVERY_EEPROM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY_EEPROM + * @brief This file includes the I2C EEPROM driver of STM32F769I-DISCOVERY board. + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_EEPROM_Exported_Types EEPROM Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_EEPROM_Exported_Constants EEPROM Exported Constants + * @{ + */ +/* EEPROM hardware address and page size */ +#define EEPROM_PAGESIZE ((uint8_t)4) +#define EEPROM_MAX_SIZE ((uint16_t)0x2000) /* 64Kbit */ + + +/* Maximum number of trials for EEPROM_WaitEepromStandbyState() function */ +#define EEPROM_MAX_TRIALS ((uint32_t)3000) + +#define EEPROM_OK ((uint32_t)0) +#define EEPROM_FAIL ((uint32_t)1) +#define EEPROM_TIMEOUT ((uint32_t)2) +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_EEPROM_Exported_Macros EEPROM Exported Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_EEPROM_Exported_Functions EEPROM Exported Functions + * @{ + */ +uint32_t BSP_EEPROM_Init(void); +uint8_t BSP_EEPROM_DeInit(void); +uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead); +uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite); +uint32_t BSP_EEPROM_WriteBuffer(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite); +uint32_t BSP_EEPROM_WaitEepromStandbyState(void); + +/* USER Callbacks: This function is declared as __weak in EEPROM driver and + should be implemented into user application. + BSP_EEPROM_TIMEOUT_UserCallback() function is called whenever a timeout condition + occurs during communication (waiting on an event that doesn't occur, bus + errors, busy devices ...). */ +void BSP_EEPROM_TIMEOUT_UserCallback(void); + +/* Link function for I2C EEPROM peripheral */ +void EEPROM_IO_Init(void); +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_DISCOVERY_EEPROM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_lcd.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_lcd.c new file mode 100644 index 00000000..9006efbf --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_lcd.c @@ -0,0 +1,1955 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_lcd.c + * @author MCD Application Team + * @brief This file includes the driver for Liquid Crystal Display (LCD) module + * mounted on STM32F769I-DISCOVERY board. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* File Info: ------------------------------------------------------------------ + User NOTES +1. How To use this driver: +-------------------------- + - This driver is used to drive directly in video mode a LCD TFT using the DSI interface. + The following IPs are implied : DSI Host IP block working + in conjunction to the LTDC controller. + - This driver is linked by construction to LCD KoD mounted on board MB1166. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the LCD using the BSP_LCD_Init() function. + o Select the LCD layer to be used using the BSP_LCD_SelectLayer() function. + o Enable the LCD display using the BSP_LCD_DisplayOn() function. + + + Options + o Configure and enable the color keying functionality using the + BSP_LCD_SetColorKeying() function. + o Modify in the fly the transparency and/or the frame buffer address + using the following functions: + - BSP_LCD_SetTransparency() + - BSP_LCD_SetLayerAddress() + + + Display on LCD + o Clear the whole LCD using BSP_LCD_Clear() function or only one specified string + line using the BSP_LCD_ClearStringLine() function. + o Display a character on the specified line and column using the BSP_LCD_DisplayChar() + function or a complete string line using the BSP_LCD_DisplayStringAtLine() function. + o Display a string line on the specified position (x,y in pixel) and align mode + using the BSP_LCD_DisplayStringAtLine() function. + o Draw and fill a basic shapes (dot, line, rectangle, circle, ellipse, .. bitmap) + on LCD using the available set of functions. + +------------------------------------------------------------------------------*/ + +/* Dependencies +- stm32f769i_discovery.c +- stm32f769i_discovery_sdram.c +- stm32f7xx_hal_dsi.c +- stm32f7xx_hal_ltdc.c +- stm32f7xx_hal_ltdc_ex.c +- stm32f7xx_hal_dma2d.c +- stm32f7xx_hal_rcc_ex.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- otm8009a.c +- adv7533.c +- fonts.h +- font24.c +- font20.c +- font16.c +- font12.c +- font8.c" +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_discovery_lcd.h" +#include "../../../Utilities/Fonts/fonts.h" +#include "../../../Utilities/Fonts/font24.c" +#include "../../../Utilities/Fonts/font20.c" +#include "../../../Utilities/Fonts/font16.c" +#include "../../../Utilities/Fonts/font12.c" +#include "../../../Utilities/Fonts/font8.c" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_LCD STM32F769I_DISCOVERY LCD + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_LCD_Private_Defines LCD Private Defines + * @{ + */ +#if defined(USE_LCD_HDMI) +#define HDMI_ASPECT_RATIO_16_9 ADV7533_ASPECT_RATIO_16_9 +#define HDMI_ASPECT_RATIO_4_3 ADV7533_ASPECT_RATIO_4_3 +#endif /* USE_LCD_HDMI */ +#define LCD_DSI_ID 0x11 +#define LCD_DSI_ID_REG 0xA8 + +static DSI_VidCfgTypeDef hdsivideo_handle; +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LCD_Private_TypesDefinitions LCD Private TypesDefinitions + * @{ + */ +#if defined(USE_LCD_HDMI) +/** + * @brief DSI timming params used for different HDMI adpater + */ +typedef struct +{ + uint16_t HACT; + uint16_t HSYNC; + uint16_t HBP; + uint16_t HFP; + uint16_t VACT; + uint16_t VSYNC; + uint16_t VBP; + uint16_t VFP; + uint8_t ASPECT_RATIO; + uint8_t RGB_CODING; +} HDMI_FormatTypeDef; + +/** + * @brief DSI packet params used for different HDMI adpater + */ +typedef struct +{ + uint16_t NullPacketSize; + uint16_t NumberOfChunks; + uint16_t PacketSize; +} HDMI_DSIPacketTypeDef; + +/** + * @brief LTDC PLL params used for different HDMI adpater + */ +typedef struct +{ + uint16_t PLLSAIN; + uint16_t PLLSAIR; + uint32_t PCLK; + uint16_t IDF; + uint16_t NDIV; + uint16_t ODF; + uint16_t LaneByteClock; + uint16_t TXEscapeCkdiv; +} HDMI_PLLConfigTypeDef; +#endif /* USE_LCD_HDMI */ +/** + * @} + */ + + + +/** @defgroup STM32F769I_DISCOVERY_LCD_Private_Macros LCD Private Macros + * @{ + */ +#define ABS(X) ((X) > 0 ? (X) : -(X)) + +#define POLY_X(Z) ((int32_t)((Points + (Z))->X)) +#define POLY_Y(Z) ((int32_t)((Points + (Z))->Y)) +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LCD_Exported_Variables STM32F769I DISCOVERY LCD Exported Variables + * @{ + */ +DMA2D_HandleTypeDef hdma2d_discovery; +LTDC_HandleTypeDef hltdc_discovery; +DSI_HandleTypeDef hdsi_discovery; +uint32_t lcd_x_size = OTM8009A_800X480_WIDTH; +uint32_t lcd_y_size = OTM8009A_800X480_HEIGHT; +/** + * @} + */ + + +/** @defgroup STM32F769I_DISCOVERY_LCD_Private_Variables LCD Private Variables + * @{ + */ +#if defined(USE_LCD_HDMI) +/** + * @brief DSI timming used for different HDMI resolution (720x480 and 720x576) + */ +HDMI_FormatTypeDef HDMI_Format[2] = +{ +/* HA HS HB HF VA VS VB VF ASPECT BPP */ + {720, 62, 60, 30, 480, 6, 19, 9, HDMI_ASPECT_RATIO_4_3, LCD_DSI_PIXEL_DATA_FMT_RBG888}, + {720, 64, 68, 12, 576, 5, 39, 5, HDMI_ASPECT_RATIO_16_9, LCD_DSI_PIXEL_DATA_FMT_RBG888} + +}; + +/** + * @brief DSI packet size used for different HDMI resolution (720x480 and 720x576) + */ +HDMI_DSIPacketTypeDef HDMI_DSIPacket[2] = +{ + /* NP NC VP */ + {0, 1, 720}, + {0, 1, 720} +}; + +/** + * @brief LTDC PLL settings used for different HDMI resolution (720x480 and 720x576) + */ +HDMI_PLLConfigTypeDef HDMI_PLLConfig[4] = +{ +/* N DIV Pclk IDF NDIV ODF LBClk TXEscapeCkdiv*/ + {325, 6, 27083, DSI_PLL_IN_DIV5, 65, DSI_PLL_OUT_DIV1, 40625, 3}, + {325, 6, 27083, DSI_PLL_IN_DIV5, 65, DSI_PLL_OUT_DIV1, 40625, 3} + +}; +#endif /* USE_LCD_HDMI */ +/** + * @brief Default Active LTDC Layer in which drawing is made is LTDC Layer Background + */ +static uint32_t ActiveLayer = LTDC_ACTIVE_LAYER_BACKGROUND; + +/** + * @brief Current Drawing Layer properties variable + */ +static LCD_DrawPropTypeDef DrawProp[LTDC_MAX_LAYER_NUMBER]; +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LCD_Private_FunctionPrototypes LCD Private FunctionPrototypes + * @{ + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c); +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3); +static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex); +static void LL_ConvertLineToARGB8888(void * pSrc, void *pDst, uint32_t xSize, uint32_t ColorMode); +static uint16_t LCD_IO_GetID(void); +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LCD_Exported_Functions LCD Exported Functions + * @{ + */ + +/** + * @brief Initializes the DSI LCD. + * @retval LCD state + */ +uint8_t BSP_LCD_Init(void) +{ + return (BSP_LCD_InitEx(LCD_ORIENTATION_LANDSCAPE)); +} + +/** + * @brief Initializes the DSI LCD. + * The ititialization is done as below: + * - DSI PLL ititialization + * - DSI ititialization + * - LTDC ititialization + * - OTM8009A LCD Display IC Driver ititialization + * @param orientation: LCD orientation, can be LCD_ORIENTATION_PORTRAIT or LCD_ORIENTATION_LANDSCAPE + * @retval LCD state + */ +uint8_t BSP_LCD_InitEx(LCD_OrientationTypeDef orientation) +{ + DSI_PLLInitTypeDef dsiPllInit; + static RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + uint32_t LcdClock = 27429; /*!< LcdClk = 27429 kHz */ + uint16_t read_id = 0; + + uint32_t laneByteClk_kHz = 0; + uint32_t VSA; /*!< Vertical start active time in units of lines */ + uint32_t VBP; /*!< Vertical Back Porch time in units of lines */ + uint32_t VFP; /*!< Vertical Front Porch time in units of lines */ + uint32_t VACT; /*!< Vertical Active time in units of lines = imageSize Y in pixels to display */ + uint32_t HSA; /*!< Horizontal start active time in units of lcdClk */ + uint32_t HBP; /*!< Horizontal Back Porch time in units of lcdClk */ + uint32_t HFP; /*!< Horizontal Front Porch time in units of lcdClk */ + uint32_t HACT; /*!< Horizontal Active time in units of lcdClk = imageSize X in pixels to display */ + + /* Toggle Hardware Reset of the DSI LCD using + * its XRES signal (active low) */ + BSP_LCD_Reset(); + + /* Check the connected monitor */ + read_id = LCD_IO_GetID(); + +#if defined(USE_LCD_HDMI) + if(read_id == ADV7533_ID) + { + return BSP_LCD_HDMIInitEx(HDMI_FORMAT_720_576); + } + else if(read_id != LCD_DSI_ID) + { + return LCD_ERROR; + } +#else + if(read_id != LCD_DSI_ID) + { + return LCD_ERROR; + } +#endif /* USE_LCD_HDMI */ + + /* Call first MSP Initialize only in case of first initialization + * This will set IP blocks LTDC, DSI and DMA2D + * - out of reset + * - clocked + * - NVIC IRQ related to IP blocks enabled + */ + BSP_LCD_MspInit(); + +/*************************DSI Initialization***********************************/ + + /* Base address of DSI Host/Wrapper registers to be set before calling De-Init */ + hdsi_discovery.Instance = DSI; + + HAL_DSI_DeInit(&(hdsi_discovery)); + + dsiPllInit.PLLNDIV = 100; + dsiPllInit.PLLIDF = DSI_PLL_IN_DIV5; + dsiPllInit.PLLODF = DSI_PLL_OUT_DIV1; + laneByteClk_kHz = 62500; /* 500 MHz / 8 = 62.5 MHz = 62500 kHz */ + + /* Set number of Lanes */ + hdsi_discovery.Init.NumberOfLanes = DSI_TWO_DATA_LANES; + + /* TXEscapeCkdiv = f(LaneByteClk)/15.62 = 4 */ + hdsi_discovery.Init.TXEscapeCkdiv = laneByteClk_kHz/15620; + + HAL_DSI_Init(&(hdsi_discovery), &(dsiPllInit)); + + /* Timing parameters for all Video modes + * Set Timing parameters of LTDC depending on its chosen orientation + */ + if(orientation == LCD_ORIENTATION_PORTRAIT) + { + lcd_x_size = OTM8009A_480X800_WIDTH; /* 480 */ + lcd_y_size = OTM8009A_480X800_HEIGHT; /* 800 */ + } + else + { + /* lcd_orientation == LCD_ORIENTATION_LANDSCAPE */ + lcd_x_size = OTM8009A_800X480_WIDTH; /* 800 */ + lcd_y_size = OTM8009A_800X480_HEIGHT; /* 480 */ + } + + HACT = lcd_x_size; + VACT = lcd_y_size; + + /* The following values are same for portrait and landscape orientations */ + VSA = OTM8009A_480X800_VSYNC; /* 12 */ + VBP = OTM8009A_480X800_VBP; /* 12 */ + VFP = OTM8009A_480X800_VFP; /* 12 */ + HSA = OTM8009A_480X800_HSYNC; /* 63 */ + HBP = OTM8009A_480X800_HBP; /* 120 */ + HFP = OTM8009A_480X800_HFP; /* 120 */ + + hdsivideo_handle.VirtualChannelID = LCD_OTM8009A_ID; + hdsivideo_handle.ColorCoding = LCD_DSI_PIXEL_DATA_FMT_RBG888; + hdsivideo_handle.VSPolarity = DSI_VSYNC_ACTIVE_HIGH; + hdsivideo_handle.HSPolarity = DSI_HSYNC_ACTIVE_HIGH; + hdsivideo_handle.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH; + hdsivideo_handle.Mode = DSI_VID_MODE_BURST; /* Mode Video burst ie : one LgP per line */ + hdsivideo_handle.NullPacketSize = 0xFFF; + hdsivideo_handle.NumberOfChunks = 0; + hdsivideo_handle.PacketSize = HACT; /* Value depending on display orientation choice portrait/landscape */ + hdsivideo_handle.HorizontalSyncActive = (HSA * laneByteClk_kHz)/LcdClock; + hdsivideo_handle.HorizontalBackPorch = (HBP * laneByteClk_kHz)/LcdClock; + hdsivideo_handle.HorizontalLine = ((HACT + HSA + HBP + HFP) * laneByteClk_kHz)/LcdClock; /* Value depending on display orientation choice portrait/landscape */ + hdsivideo_handle.VerticalSyncActive = VSA; + hdsivideo_handle.VerticalBackPorch = VBP; + hdsivideo_handle.VerticalFrontPorch = VFP; + hdsivideo_handle.VerticalActive = VACT; /* Value depending on display orientation choice portrait/landscape */ + + /* Enable or disable sending LP command while streaming is active in video mode */ + hdsivideo_handle.LPCommandEnable = DSI_LP_COMMAND_ENABLE; /* Enable sending commands in mode LP (Low Power) */ + + /* Largest packet size possible to transmit in LP mode in VSA, VBP, VFP regions */ + /* Only useful when sending LP packets is allowed while streaming is active in video mode */ + hdsivideo_handle.LPLargestPacketSize = 16; + + /* Largest packet size possible to transmit in LP mode in HFP region during VACT period */ + /* Only useful when sending LP packets is allowed while streaming is active in video mode */ + hdsivideo_handle.LPVACTLargestPacketSize = 0; + + /* Specify for each region of the video frame, if the transmission of command in LP mode is allowed in this region */ + /* while streaming is active in video mode */ + hdsivideo_handle.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE; /* Allow sending LP commands during HFP period */ + hdsivideo_handle.LPHorizontalBackPorchEnable = DSI_LP_HBP_ENABLE; /* Allow sending LP commands during HBP period */ + hdsivideo_handle.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE; /* Allow sending LP commands during VACT period */ + hdsivideo_handle.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE; /* Allow sending LP commands during VFP period */ + hdsivideo_handle.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE; /* Allow sending LP commands during VBP period */ + hdsivideo_handle.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE; /* Allow sending LP commands during VSync = VSA period */ + + /* Configure DSI Video mode timings with settings set above */ + HAL_DSI_ConfigVideoMode(&(hdsi_discovery), &(hdsivideo_handle)); + +/*************************End DSI Initialization*******************************/ + + +/************************LTDC Initialization***********************************/ + + /* Timing Configuration */ + hltdc_discovery.Init.HorizontalSync = (HSA - 1); + hltdc_discovery.Init.AccumulatedHBP = (HSA + HBP - 1); + hltdc_discovery.Init.AccumulatedActiveW = (lcd_x_size + HSA + HBP - 1); + hltdc_discovery.Init.TotalWidth = (lcd_x_size + HSA + HBP + HFP - 1); + + /* Initialize the LCD pixel width and pixel height */ + hltdc_discovery.LayerCfg->ImageWidth = lcd_x_size; + hltdc_discovery.LayerCfg->ImageHeight = lcd_y_size; + + /** LCD clock configuration + * Note: The following values should not be changed as the PLLSAI is also used + * to clock the USB FS + * PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz + * PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 384 Mhz + * PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 384 MHz / 7 = 54.85 MHz + * LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_2 = 54.85 MHz / 2 = 27.429 MHz + */ + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; + PeriphClkInitStruct.PLLSAI.PLLSAIN = 384; + PeriphClkInitStruct.PLLSAI.PLLSAIR = 7; + PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_2; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); + + /* Background value */ + hltdc_discovery.Init.Backcolor.Blue = 0; + hltdc_discovery.Init.Backcolor.Green = 0; + hltdc_discovery.Init.Backcolor.Red = 0; + hltdc_discovery.Init.PCPolarity = LTDC_PCPOLARITY_IPC; + hltdc_discovery.Instance = LTDC; + + /* Get LTDC Configuration from DSI Configuration */ + HAL_LTDC_StructInitFromVideoConfig(&(hltdc_discovery), &(hdsivideo_handle)); + + /* Initialize the LTDC */ + HAL_LTDC_Init(&hltdc_discovery); + + /* Enable the DSI host and wrapper after the LTDC initialization + To avoid any synchronization issue, the DSI shall be started after enabling the LTDC */ + HAL_DSI_Start(&hdsi_discovery); + +#if !defined(DATA_IN_ExtSDRAM) + /* Initialize the SDRAM */ + BSP_SDRAM_Init(); +#endif /* DATA_IN_ExtSDRAM */ + + /* Initialize the font */ + BSP_LCD_SetFont(&LCD_DEFAULT_FONT); + +/************************End LTDC Initialization*******************************/ + + +/***********************OTM8009A Initialization********************************/ + + /* Initialize the OTM8009A LCD Display IC Driver (KoD LCD IC Driver) + * depending on configuration set in 'hdsivideo_handle'. + */ + OTM8009A_Init(OTM8009A_FORMAT_RGB888, orientation); + +/***********************End OTM8009A Initialization****************************/ + + return LCD_OK; +} + +#if defined(USE_LCD_HDMI) +/** + * @brief Initializes the DSI for HDMI monitor. + * The ititialization is done as below: + * - DSI PLL ititialization + * - DSI ititialization + * - LTDC ititialization + * - DSI-HDMI ADV7533 adapter device ititialization + * @param format : HDMI format could be HDMI_FORMAT_720_480 or HDMI_FORMAT_720_576 + * @retval LCD state + */ +uint8_t BSP_LCD_HDMIInitEx(uint8_t format) +{ + /************************ADV7533 Initialization********************************/ + + /* Initialize the ADV7533 HDMI Bridge + * depending on configuration set in 'hdsivideo_handle'. + */ + adv7533ConfigTypeDef adv7533_config; + + adv7533_config.DSI_LANES = 2; + adv7533_config.HACT = HDMI_Format[format].HACT; + adv7533_config.HSYNC = HDMI_Format[format].HSYNC; + adv7533_config.HBP = HDMI_Format[format].HBP; + adv7533_config.HFP = HDMI_Format[format].HFP; + adv7533_config.VACT = HDMI_Format[format].VACT; + adv7533_config.VSYNC = HDMI_Format[format].VSYNC; + adv7533_config.VBP = HDMI_Format[format].VBP; + adv7533_config.VFP = HDMI_Format[format].VFP; + + ADV7533_Init(); + ADV7533_Configure(&adv7533_config); + ADV7533_PowerOn(); + +/************************ Update hdmi_x_size and hdmi_y_size *****************/ + lcd_x_size = HDMI_Format[format].HACT; + lcd_y_size = HDMI_Format[format].VACT; + +/***********************End ADV7533 Initialization****************************/ + DSI_PLLInitTypeDef dsiPllInit; + DSI_PHY_TimerTypeDef dsiPhyInit; + static RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + + /* Call first MSP Initialize only in case of first initialization + * This will set IP blocks LTDC and DSI + * - out of reset + * - clocked + * - NVIC IRQ related to IP blocks enabled + */ + BSP_LCD_MspInit(); + +/*************************DSI Initialization***********************************/ + + /* Base address of DSI Host/Wrapper registers to be set before calling De-Init */ + hdsi_discovery.Instance = DSI; + + HAL_DSI_DeInit(&(hdsi_discovery)); + + /* Configure the DSI PLL */ + dsiPllInit.PLLNDIV = HDMI_PLLConfig[format].NDIV; + dsiPllInit.PLLIDF = HDMI_PLLConfig[format].IDF; + dsiPllInit.PLLODF = HDMI_PLLConfig[format].ODF; + + /* Set number of Lanes */ + hdsi_discovery.Init.NumberOfLanes = DSI_TWO_DATA_LANES; + /* Set the TX escape clock division ratio */ + hdsi_discovery.Init.TXEscapeCkdiv = HDMI_PLLConfig[format].TXEscapeCkdiv; + /* Disable the automatic clock lane control (the ADV7533 must be clocked) */ + hdsi_discovery.Init.AutomaticClockLaneControl = DSI_AUTO_CLK_LANE_CTRL_DISABLE; + + /* Init the DSI */ + HAL_DSI_Init(&hdsi_discovery, &dsiPllInit); + + /* Configure the D-PHY Timings */ + dsiPhyInit.ClockLaneHS2LPTime = 0x14; + dsiPhyInit.ClockLaneLP2HSTime = 0x14; + dsiPhyInit.DataLaneHS2LPTime = 0x0A; + dsiPhyInit.DataLaneLP2HSTime = 0x0A; + dsiPhyInit.DataLaneMaxReadTime = 0x00; + dsiPhyInit.StopWaitTime = 0x0; + HAL_DSI_ConfigPhyTimer(&hdsi_discovery, &dsiPhyInit); + + /* Virutal channel used by the ADV7533 */ + hdsivideo_handle.VirtualChannelID = HDMI_ADV7533_ID; + + /* Timing parameters for Video modes + Set Timing parameters of DSI depending on its chosen format */ + hdsivideo_handle.ColorCoding = HDMI_Format[format].RGB_CODING; + hdsivideo_handle.LooselyPacked = DSI_LOOSELY_PACKED_DISABLE; + hdsivideo_handle.VSPolarity = DSI_VSYNC_ACTIVE_LOW; + hdsivideo_handle.HSPolarity = DSI_HSYNC_ACTIVE_LOW; + hdsivideo_handle.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH; + hdsivideo_handle.Mode = DSI_VID_MODE_NB_PULSES; + hdsivideo_handle.NullPacketSize = HDMI_DSIPacket[format].NullPacketSize; + hdsivideo_handle.NumberOfChunks = HDMI_DSIPacket[format].NumberOfChunks; + hdsivideo_handle.PacketSize = HDMI_DSIPacket[format].PacketSize; + hdsivideo_handle.HorizontalSyncActive = HDMI_Format[format].HSYNC*HDMI_PLLConfig[format].LaneByteClock/HDMI_PLLConfig[format].PCLK; + hdsivideo_handle.HorizontalBackPorch = HDMI_Format[format].HBP*HDMI_PLLConfig[format].LaneByteClock/HDMI_PLLConfig[format].PCLK; + hdsivideo_handle.HorizontalLine = (HDMI_Format[format].HACT + HDMI_Format[format].HSYNC + HDMI_Format[format].HBP + HDMI_Format[format].HFP)*HDMI_PLLConfig[format].LaneByteClock/HDMI_PLLConfig[format].PCLK; + hdsivideo_handle.VerticalSyncActive = HDMI_Format[format].VSYNC; + hdsivideo_handle.VerticalBackPorch = HDMI_Format[format].VBP; + hdsivideo_handle.VerticalFrontPorch = HDMI_Format[format].VFP; + hdsivideo_handle.VerticalActive = HDMI_Format[format].VACT; + + /* Enable or disable sending LP command while streaming is active in video mode */ + hdsivideo_handle.LPCommandEnable = DSI_LP_COMMAND_DISABLE; /* Enable sending commands in mode LP (Low Power) */ + + /* Largest packet size possible to transmit in LP mode in VSA, VBP, VFP regions */ + /* Only useful when sending LP packets is allowed while streaming is active in video mode */ + hdsivideo_handle.LPLargestPacketSize = 4; + + /* Largest packet size possible to transmit in LP mode in HFP region during VACT period */ + /* Only useful when sending LP packets is allowed while streaming is active in video mode */ + hdsivideo_handle.LPVACTLargestPacketSize = 4; + + /* Specify for each region, if the going in LP mode is allowed */ + /* while streaming is active in video mode */ + hdsivideo_handle.LPHorizontalFrontPorchEnable = DSI_LP_HFP_DISABLE; + hdsivideo_handle.LPHorizontalBackPorchEnable = DSI_LP_HBP_DISABLE; + hdsivideo_handle.LPVerticalActiveEnable = DSI_LP_VACT_DISABLE; + hdsivideo_handle.LPVerticalFrontPorchEnable = DSI_LP_VFP_DISABLE; + hdsivideo_handle.LPVerticalBackPorchEnable = DSI_LP_VBP_DISABLE; + hdsivideo_handle.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_DISABLE; + + /* No acknoledge at the end of a frame */ + hdsivideo_handle.FrameBTAAcknowledgeEnable = DSI_FBTAA_DISABLE; + + /* Configure DSI Video mode timings with settings set above */ + HAL_DSI_ConfigVideoMode(&hdsi_discovery, &hdsivideo_handle); + + /* Enable the DSI host and wrapper : but LTDC is not started yet at this stage */ + HAL_DSI_Start(&hdsi_discovery); + +/*************************End DSI Initialization*******************************/ + + +/************************LTDC Initialization***********************************/ + + /* LTDC clock configuration */ + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; + PeriphClkInitStruct.PLLSAI.PLLSAIN = HDMI_PLLConfig[format].PLLSAIN; + PeriphClkInitStruct.PLLSAI.PLLSAIR = HDMI_PLLConfig[format].PLLSAIR; + PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_2; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); + + /* Base address of LTDC registers to be set before calling De-Init */ + hltdc_discovery.Instance = LTDC; + + HAL_LTDC_DeInit(&(hltdc_discovery)); + + /* Timing Configuration */ + hltdc_discovery.Init.HorizontalSync = (HDMI_Format[format].HSYNC - 1); + hltdc_discovery.Init.AccumulatedHBP = (HDMI_Format[format].HSYNC + HDMI_Format[format].HBP - 1); + hltdc_discovery.Init.AccumulatedActiveW = (HDMI_Format[format].HACT + HDMI_Format[format].HSYNC + HDMI_Format[format].HBP - 1); + hltdc_discovery.Init.TotalWidth = (HDMI_Format[format].HACT + HDMI_Format[format].HSYNC + HDMI_Format[format].HBP + HDMI_Format[format].HFP - 1); + hltdc_discovery.Init.VerticalSync = (HDMI_Format[format].VSYNC - 1); + hltdc_discovery.Init.AccumulatedVBP = (HDMI_Format[format].VSYNC + HDMI_Format[format].VBP - 1); + hltdc_discovery.Init.AccumulatedActiveH = (HDMI_Format[format].VACT + HDMI_Format[format].VSYNC + HDMI_Format[format].VBP - 1); + hltdc_discovery.Init.TotalHeigh = (HDMI_Format[format].VACT + HDMI_Format[format].VSYNC + HDMI_Format[format].VBP + HDMI_Format[format].VFP - 1); + + /* background value */ + hltdc_discovery.Init.Backcolor.Blue = 0x00; + hltdc_discovery.Init.Backcolor.Green = 0xFF; + hltdc_discovery.Init.Backcolor.Red = 0xFF; + + /* Polarity */ + hltdc_discovery.Init.HSPolarity = LTDC_HSPOLARITY_AL; + hltdc_discovery.Init.VSPolarity = LTDC_VSPOLARITY_AL; + hltdc_discovery.Init.DEPolarity = LTDC_DEPOLARITY_AL; + hltdc_discovery.Init.PCPolarity = LTDC_PCPOLARITY_IPC; + + /* Initialize & Start the LTDC */ + HAL_LTDC_Init(&hltdc_discovery); + +#if !defined(DATA_IN_ExtSDRAM) + /* Initialize the SDRAM */ + BSP_SDRAM_Init(); +#endif /* DATA_IN_ExtSDRAM */ + + /* Initialize the font */ + BSP_LCD_SetFont(&LCD_DEFAULT_FONT); +/************************End LTDC Initialization*******************************/ + + return LCD_OK; +} +#endif /* USE_LCD_HDMI */ + +/** + * @brief BSP LCD Reset + * Hw reset the LCD DSI activating its XRES signal (active low for some time) + * and desactivating it later. + */ +void BSP_LCD_Reset(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + __HAL_RCC_GPIOJ_CLK_ENABLE(); + + /* Configure the GPIO on PJ15 */ + gpio_init_structure.Pin = GPIO_PIN_15; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + + HAL_GPIO_Init(GPIOJ, &gpio_init_structure); + + /* Activate XRES active low */ + HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_15, GPIO_PIN_RESET); + + HAL_Delay(20); /* wait 20 ms */ + + /* Desactivate XRES */ + HAL_GPIO_WritePin(GPIOJ, GPIO_PIN_15, GPIO_PIN_SET); + + /* Wait for 10ms after releasing XRES before sending commands */ + HAL_Delay(10); +} + +/** + * @brief Gets the LCD X size. + * @retval Used LCD X size + */ +uint32_t BSP_LCD_GetXSize(void) +{ + return (lcd_x_size); +} + +/** + * @brief Gets the LCD Y size. + * @retval Used LCD Y size + */ +uint32_t BSP_LCD_GetYSize(void) +{ + return (lcd_y_size); +} + +/** + * @brief Set the LCD X size. + * @param imageWidthPixels : uint32_t image width in pixels unit + * @retval None + */ +void BSP_LCD_SetXSize(uint32_t imageWidthPixels) +{ + hltdc_discovery.LayerCfg[ActiveLayer].ImageWidth = imageWidthPixels; +} + +/** + * @brief Set the LCD Y size. + * @param imageHeightPixels : uint32_t image height in lines unit + */ +void BSP_LCD_SetYSize(uint32_t imageHeightPixels) +{ + hltdc_discovery.LayerCfg[ActiveLayer].ImageHeight = imageHeightPixels; +} + + +/** + * @brief Initializes the LCD layers. + * @param LayerIndex: Layer foreground or background + * @param FB_Address: Layer frame buffer + * @retval None + */ +void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) +{ + LCD_LayerCfgTypeDef Layercfg; + + /* Layer Init */ + Layercfg.WindowX0 = 0; + Layercfg.WindowX1 = BSP_LCD_GetXSize(); + Layercfg.WindowY0 = 0; + Layercfg.WindowY1 = BSP_LCD_GetYSize(); + Layercfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888; + Layercfg.FBStartAdress = FB_Address; + Layercfg.Alpha = 255; + Layercfg.Alpha0 = 0; + Layercfg.Backcolor.Blue = 0; + Layercfg.Backcolor.Green = 0; + Layercfg.Backcolor.Red = 0; + Layercfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; + Layercfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; + Layercfg.ImageWidth = BSP_LCD_GetXSize(); + Layercfg.ImageHeight = BSP_LCD_GetYSize(); + + HAL_LTDC_ConfigLayer(&hltdc_discovery, &Layercfg, LayerIndex); + + DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE; + DrawProp[LayerIndex].pFont = &Font24; + DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK; +} + + +/** + * @brief Selects the LCD Layer. + * @param LayerIndex: Layer foreground or background + */ +void BSP_LCD_SelectLayer(uint32_t LayerIndex) +{ + ActiveLayer = LayerIndex; +} + +/** + * @brief Sets an LCD Layer visible + * @param LayerIndex: Visible Layer + * @param State: New state of the specified layer + * This parameter can be one of the following values: + * @arg ENABLE + * @arg DISABLE + */ +void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState State) +{ + if(State == ENABLE) + { + __HAL_LTDC_LAYER_ENABLE(&(hltdc_discovery), LayerIndex); + } + else + { + __HAL_LTDC_LAYER_DISABLE(&(hltdc_discovery), LayerIndex); + } + __HAL_LTDC_RELOAD_CONFIG(&(hltdc_discovery)); + +} + +/** + * @brief Configures the transparency. + * @param LayerIndex: Layer foreground or background. + * @param Transparency: Transparency + * This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF + */ +void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency) +{ + + HAL_LTDC_SetAlpha(&(hltdc_discovery), Transparency, LayerIndex); + +} + +/** + * @brief Sets an LCD layer frame buffer address. + * @param LayerIndex: Layer foreground or background + * @param Address: New LCD frame buffer value + */ +void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address) +{ + + HAL_LTDC_SetAddress(&(hltdc_discovery), Address, LayerIndex); + +} + +/** + * @brief Sets display window. + * @param LayerIndex: Layer index + * @param Xpos: LCD X position + * @param Ypos: LCD Y position + * @param Width: LCD window width + * @param Height: LCD window height + */ +void BSP_LCD_SetLayerWindow(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Reconfigure the layer size */ + HAL_LTDC_SetWindowSize(&(hltdc_discovery), Width, Height, LayerIndex); + + /* Reconfigure the layer position */ + HAL_LTDC_SetWindowPosition(&(hltdc_discovery), Xpos, Ypos, LayerIndex); + +} + +/** + * @brief Configures and sets the color keying. + * @param LayerIndex: Layer foreground or background + * @param RGBValue: Color reference + */ +void BSP_LCD_SetColorKeying(uint32_t LayerIndex, uint32_t RGBValue) +{ + /* Configure and Enable the color Keying for LCD Layer */ + HAL_LTDC_ConfigColorKeying(&(hltdc_discovery), RGBValue, LayerIndex); + HAL_LTDC_EnableColorKeying(&(hltdc_discovery), LayerIndex); +} + +/** + * @brief Disables the color keying. + * @param LayerIndex: Layer foreground or background + */ +void BSP_LCD_ResetColorKeying(uint32_t LayerIndex) +{ + /* Disable the color Keying for LCD Layer */ + HAL_LTDC_DisableColorKeying(&(hltdc_discovery), LayerIndex); +} + +/** + * @brief Sets the LCD text color. + * @param Color: Text color code ARGB(8-8-8-8) + */ +void BSP_LCD_SetTextColor(uint32_t Color) +{ + DrawProp[ActiveLayer].TextColor = Color; +} + +/** + * @brief Gets the LCD text color. + * @retval Used text color. + */ +uint32_t BSP_LCD_GetTextColor(void) +{ + return DrawProp[ActiveLayer].TextColor; +} + +/** + * @brief Sets the LCD background color. + * @param Color: Layer background color code ARGB(8-8-8-8) + */ +void BSP_LCD_SetBackColor(uint32_t Color) +{ + DrawProp[ActiveLayer].BackColor = Color; +} + +/** + * @brief Gets the LCD background color. + * @retval Used background color + */ +uint32_t BSP_LCD_GetBackColor(void) +{ + return DrawProp[ActiveLayer].BackColor; +} + +/** + * @brief Sets the LCD text font. + * @param fonts: Layer font to be used + */ +void BSP_LCD_SetFont(sFONT *fonts) +{ + DrawProp[ActiveLayer].pFont = fonts; +} + +/** + * @brief Gets the LCD text font. + * @retval Used layer font + */ +sFONT *BSP_LCD_GetFont(void) +{ + return DrawProp[ActiveLayer].pFont; +} + +/** + * @brief Reads an LCD pixel. + * @param Xpos: X position + * @param Ypos: Y position + * @retval RGB pixel color + */ +uint32_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos) +{ + uint32_t ret = 0; + + if(hltdc_discovery.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint32_t*) (hltdc_discovery.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + else if(hltdc_discovery.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB888) + { + /* Read data value from SDRAM memory */ + ret = (*(__IO uint32_t*) (hltdc_discovery.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))) & 0x00FFFFFF); + } + else if((hltdc_discovery.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \ + (hltdc_discovery.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \ + (hltdc_discovery.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_AL88)) + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint16_t*) (hltdc_discovery.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + else + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint8_t*) (hltdc_discovery.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + + return ret; +} + +/** + * @brief Clears the whole currently active layer of LTDC. + * @param Color: Color of the background + */ +void BSP_LCD_Clear(uint32_t Color) +{ + /* Clear the LCD */ + LL_FillBuffer(ActiveLayer, (uint32_t *)(hltdc_discovery.LayerCfg[ActiveLayer].FBStartAdress), BSP_LCD_GetXSize(), BSP_LCD_GetYSize(), 0, Color); +} + +/** + * @brief Clears the selected line in currently active layer. + * @param Line: Line to be cleared + */ +void BSP_LCD_ClearStringLine(uint32_t Line) +{ + uint32_t color_backup = DrawProp[ActiveLayer].TextColor; + DrawProp[ActiveLayer].TextColor = DrawProp[ActiveLayer].BackColor; + + /* Draw rectangle with background color */ + BSP_LCD_FillRect(0, (Line * DrawProp[ActiveLayer].pFont->Height), BSP_LCD_GetXSize(), DrawProp[ActiveLayer].pFont->Height); + + DrawProp[ActiveLayer].TextColor = color_backup; + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Displays one character in currently active layer. + * @param Xpos: Start column address + * @param Ypos: Line where to display the character shape. + * @param Ascii: Character ascii code + * This parameter must be a number between Min_Data = 0x20 and Max_Data = 0x7E + */ +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii) +{ + DrawChar(Xpos, Ypos, &DrawProp[ActiveLayer].pFont->table[(Ascii-' ') *\ + DrawProp[ActiveLayer].pFont->Height * ((DrawProp[ActiveLayer].pFont->Width + 7) / 8)]); +} + +/** + * @brief Displays characters in currently active layer. + * @param Xpos: X position (in pixel) + * @param Ypos: Y position (in pixel) + * @param Text: Pointer to string to display on LCD + * @param Mode: Display mode + * This parameter can be one of the following values: + * @arg CENTER_MODE + * @arg RIGHT_MODE + * @arg LEFT_MODE + */ +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode) +{ + uint16_t refcolumn = 1, i = 0; + uint32_t size = 0, xsize = 0; + uint8_t *ptr = Text; + + /* Get the text size */ + while (*ptr++) size ++ ; + + /* Characters number per line */ + xsize = (BSP_LCD_GetXSize()/DrawProp[ActiveLayer].pFont->Width); + + switch (Mode) + { + case CENTER_MODE: + { + refcolumn = Xpos + ((xsize - size)* DrawProp[ActiveLayer].pFont->Width) / 2; + break; + } + case LEFT_MODE: + { + refcolumn = Xpos; + break; + } + case RIGHT_MODE: + { + refcolumn = - Xpos + ((xsize - size)*DrawProp[ActiveLayer].pFont->Width); + break; + } + default: + { + refcolumn = Xpos; + break; + } + } + + /* Check that the Start column is located in the screen */ + if ((refcolumn < 1) || (refcolumn >= 0x8000)) + { + refcolumn = 1; + } + + /* Send the string character by character on LCD */ + while ((*Text != 0) & (((BSP_LCD_GetXSize() - (i*DrawProp[ActiveLayer].pFont->Width)) & 0xFFFF) >= DrawProp[ActiveLayer].pFont->Width)) + { + /* Display one character on LCD */ + BSP_LCD_DisplayChar(refcolumn, Ypos, *Text); + /* Decrement the column position by 16 */ + refcolumn += DrawProp[ActiveLayer].pFont->Width; + + /* Point on the next character */ + Text++; + i++; + } + +} + +/** + * @brief Displays a maximum of 60 characters on the LCD. + * @param Line: Line where to display the character shape + * @param ptr: Pointer to string to display on LCD + */ +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr) +{ + BSP_LCD_DisplayStringAt(0, LINE(Line), ptr, LEFT_MODE); +} + +/** + * @brief Draws an horizontal line in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + */ +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t Xaddress = 0; + + /* Get the line address */ + Xaddress = (hltdc_discovery.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + + /* Write line */ + LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, Length, 1, 0, DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws a vertical line in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + */ +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t Xaddress = 0; + + /* Get the line address */ + Xaddress = (hltdc_discovery.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + + /* Write line */ + LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, 1, Length, (BSP_LCD_GetXSize() - 1), DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws an uni-line (between two points) in currently active layer. + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + */ +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + numadd = deltay; + numpixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + numadd = deltax; + numpixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= numpixels; curpixel++) + { + BSP_LCD_DrawPixel(x, y, DrawProp[ActiveLayer].TextColor); /* Draw the current pixel */ + num += numadd; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Draws a rectangle in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + */ +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Draw horizontal lines */ + BSP_LCD_DrawHLine(Xpos, Ypos, Width); + BSP_LCD_DrawHLine(Xpos, (Ypos+ Height), Width); + + /* Draw vertical lines */ + BSP_LCD_DrawVLine(Xpos, Ypos, Height); + BSP_LCD_DrawVLine((Xpos + Width), Ypos, Height); +} + +/** + * @brief Draws a circle in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + */ +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t D; /* Decision Variable */ + uint32_t CurX; /* Current X Value */ + uint32_t CurY; /* Current Y Value */ + + D = 3 - (Radius << 1); + CurX = 0; + CurY = Radius; + + while (CurX <= CurY) + { + BSP_LCD_DrawPixel((Xpos + CurX), (Ypos - CurY), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - CurX), (Ypos - CurY), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + CurY), (Ypos - CurX), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - CurY), (Ypos - CurX), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + CurX), (Ypos + CurY), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - CurX), (Ypos + CurY), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + CurY), (Ypos + CurX), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - CurY), (Ypos + CurX), DrawProp[ActiveLayer].TextColor); + + if (D < 0) + { + D += (CurX << 2) + 6; + } + else + { + D += ((CurX - CurY) << 2) + 10; + CurY--; + } + CurX++; + } +} + +/** + * @brief Draws an poly-line (between many points) in currently active layer. + * @param Points: Pointer to the points array + * @param PointCount: Number of points + */ +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t X = 0, Y = 0; + + if(PointCount < 2) + { + return; + } + + BSP_LCD_DrawLine(Points->X, Points->Y, (Points+PointCount-1)->X, (Points+PointCount-1)->Y); + + while(--PointCount) + { + X = Points->X; + Y = Points->Y; + Points++; + BSP_LCD_DrawLine(X, Y, Points->X, Points->Y); + } +} + +/** + * @brief Draws an ellipse on LCD in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + */ +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float K = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + K = (float)(rad2/rad1); + + do { + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/K)), (Ypos+y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/K)), (Ypos+y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/K)), (Ypos-y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/K)), (Ypos-y), DrawProp[ActiveLayer].TextColor); + + e2 = err; + if (e2 <= x) { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Draws a bitmap picture loaded in the internal Flash (32 bpp) in currently active layer. + * @param Xpos: Bmp X position in the LCD + * @param Ypos: Bmp Y position in the LCD + * @param pbmp: Pointer to Bmp picture address in the internal Flash + */ +void BSP_LCD_DrawBitmap(uint32_t Xpos, uint32_t Ypos, uint8_t *pbmp) +{ + uint32_t index = 0, width = 0, height = 0, bit_pixel = 0; + uint32_t Address; + uint32_t InputColorMode = 0; + + /* Get bitmap data address offset */ + index = pbmp[10] + (pbmp[11] << 8) + (pbmp[12] << 16) + (pbmp[13] << 24); + + /* Read bitmap width */ + width = pbmp[18] + (pbmp[19] << 8) + (pbmp[20] << 16) + (pbmp[21] << 24); + + /* Read bitmap height */ + height = pbmp[22] + (pbmp[23] << 8) + (pbmp[24] << 16) + (pbmp[25] << 24); + + /* Read bit/pixel */ + bit_pixel = pbmp[28] + (pbmp[29] << 8); + + /* Set the address */ + Address = hltdc_discovery.LayerCfg[ActiveLayer].FBStartAdress + (((BSP_LCD_GetXSize()*Ypos) + Xpos)*(4)); + + /* Get the layer pixel format */ + if ((bit_pixel/8) == 4) + { + InputColorMode = DMA2D_INPUT_ARGB8888; + } + else if ((bit_pixel/8) == 2) + { + InputColorMode = DMA2D_INPUT_RGB565; + } + else + { + InputColorMode = DMA2D_INPUT_RGB888; + } + + /* Bypass the bitmap header */ + pbmp += (index + (width * (height - 1) * (bit_pixel/8))); + + /* Convert picture to ARGB8888 pixel format */ + for(index=0; index < height; index++) + { + /* Pixel format conversion */ + LL_ConvertLineToARGB8888((uint32_t *)pbmp, (uint32_t *)Address, width, InputColorMode); + + /* Increment the source and destination buffers */ + Address+= (BSP_LCD_GetXSize()*4); + pbmp -= width*(bit_pixel/8); + } +} + +/** + * @brief Draws a full rectangle in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + */ +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + uint32_t Xaddress = 0; + + /* Set the text color */ + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + + /* Get the rectangle start address */ + Xaddress = (hltdc_discovery.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + + /* Fill the rectangle */ + LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, Width, Height, (BSP_LCD_GetXSize() - Width), DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws a full circle in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + */ +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t D; /* Decision Variable */ + uint32_t CurX; /* Current X Value */ + uint32_t CurY; /* Current Y Value */ + + D = 3 - (Radius << 1); + + CurX = 0; + CurY = Radius; + + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + + while (CurX <= CurY) + { + if(CurY > 0) + { + BSP_LCD_DrawHLine(Xpos - CurY, Ypos + CurX, 2*CurY); + BSP_LCD_DrawHLine(Xpos - CurY, Ypos - CurX, 2*CurY); + } + + if(CurX > 0) + { + BSP_LCD_DrawHLine(Xpos - CurX, Ypos - CurY, 2*CurX); + BSP_LCD_DrawHLine(Xpos - CurX, Ypos + CurY, 2*CurX); + } + if (D < 0) + { + D += (CurX << 2) + 6; + } + else + { + D += ((CurX - CurY) << 2) + 10; + CurY--; + } + CurX++; + } + + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawCircle(Xpos, Ypos, Radius); +} + +/** + * @brief Draws a full poly-line (between many points) in currently active layer. + * @param Points: Pointer to the points array + * @param PointCount: Number of points + */ +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t X = 0, Y = 0, X2 = 0, Y2 = 0, X_center = 0, Y_center = 0, X_first = 0, Y_first = 0, pixelX = 0, pixelY = 0, counter = 0; + uint16_t IMAGE_LEFT = 0, IMAGE_RIGHT = 0, IMAGE_TOP = 0, IMAGE_BOTTOM = 0; + + IMAGE_LEFT = IMAGE_RIGHT = Points->X; + IMAGE_TOP= IMAGE_BOTTOM = Points->Y; + + for(counter = 1; counter < PointCount; counter++) + { + pixelX = POLY_X(counter); + if(pixelX < IMAGE_LEFT) + { + IMAGE_LEFT = pixelX; + } + if(pixelX > IMAGE_RIGHT) + { + IMAGE_RIGHT = pixelX; + } + + pixelY = POLY_Y(counter); + if(pixelY < IMAGE_TOP) + { + IMAGE_TOP = pixelY; + } + if(pixelY > IMAGE_BOTTOM) + { + IMAGE_BOTTOM = pixelY; + } + } + + if(PointCount < 2) + { + return; + } + + X_center = (IMAGE_LEFT + IMAGE_RIGHT)/2; + Y_center = (IMAGE_BOTTOM + IMAGE_TOP)/2; + + X_first = Points->X; + Y_first = Points->Y; + + while(--PointCount) + { + X = Points->X; + Y = Points->Y; + Points++; + X2 = Points->X; + Y2 = Points->Y; + + FillTriangle(X, X2, X_center, Y, Y2, Y_center); + FillTriangle(X, X_center, X2, Y, Y_center, Y2); + FillTriangle(X_center, X2, X, Y_center, Y2, Y); + } + + FillTriangle(X_first, X2, X_center, Y_first, Y2, Y_center); + FillTriangle(X_first, X_center, X2, Y_first, Y_center, Y2); + FillTriangle(X_center, X2, X_first, Y_center, Y2, Y_first); +} + +/** + * @brief Draws a full ellipse in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + */ +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float K = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + K = (float)(rad2/rad1); + + do + { + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/K)), (Ypos+y), (2*(uint16_t)(x/K) + 1)); + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/K)), (Ypos-y), (2*(uint16_t)(x/K) + 1)); + + e2 = err; + if (e2 <= x) + { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Switch back on the display if was switched off by previous call of BSP_LCD_DisplayOff(). + * Exit DSI ULPM mode if was allowed and configured in Dsi Configuration. + */ +void BSP_LCD_DisplayOn(void) +{ +#if defined(USE_LCD_HDMI) + if(ADV7533_ID == adv7533_drv.ReadID(ADV7533_CEC_DSI_I2C_ADDR)) + { + return ; /* Not supported for HDMI display */ + } + else +#endif /* USE_LCD_HDMI */ + { + /* Send Display on DCS command to display */ + HAL_DSI_ShortWrite(&(hdsi_discovery), + hdsivideo_handle.VirtualChannelID, + DSI_DCS_SHORT_PKT_WRITE_P1, + OTM8009A_CMD_DISPON, + 0x00); + } +} + +/** + * @brief Switch Off the display. + * Enter DSI ULPM mode if was allowed and configured in Dsi Configuration. + */ +void BSP_LCD_DisplayOff(void) +{ +#if defined(USE_LCD_HDMI) + if(ADV7533_ID == adv7533_drv.ReadID(ADV7533_CEC_DSI_I2C_ADDR)) + { + return ; /* Not supported for HDMI display */ + } + else +#endif /* USE_LCD_HDMI */ + { + /* Send Display off DCS Command to display */ + HAL_DSI_ShortWrite(&(hdsi_discovery), + hdsivideo_handle.VirtualChannelID, + DSI_DCS_SHORT_PKT_WRITE_P1, + OTM8009A_CMD_DISPOFF, + 0x00); + } +} + +/** + * @brief Set the brightness value + * @param BrightnessValue: [00: Min (black), 100 Max] + */ +void BSP_LCD_SetBrightness(uint8_t BrightnessValue) +{ +#if defined(USE_LCD_HDMI) + if(ADV7533_ID == adv7533_drv.ReadID(ADV7533_CEC_DSI_I2C_ADDR)) + { + return ; /* Not supported for HDMI display */ + } + else +#endif /* USE_LCD_HDMI */ + { + /* Send Display on DCS command to display */ + HAL_DSI_ShortWrite(&hdsi_discovery, + LCD_OTM8009A_ID, + DSI_DCS_SHORT_PKT_WRITE_P1, + OTM8009A_CMD_WRDISBV, (uint16_t)(BrightnessValue * 255)/100); + } +} + +/** + * @brief DCS or Generic short/long write command + * @param NbrParams: Number of parameters. It indicates the write command mode: + * If inferior to 2, a long write command is performed else short. + * @param pParams: Pointer to parameter values table. + * @retval HAL status + */ +void DSI_IO_WriteCmd(uint32_t NbrParams, uint8_t *pParams) +{ + if(NbrParams <= 1) + { + HAL_DSI_ShortWrite(&hdsi_discovery, LCD_OTM8009A_ID, DSI_DCS_SHORT_PKT_WRITE_P1, pParams[0], pParams[1]); + } + else + { + HAL_DSI_LongWrite(&hdsi_discovery, LCD_OTM8009A_ID, DSI_DCS_LONG_PKT_WRITE, NbrParams, pParams[NbrParams], pParams); + } +} + +/** + * @brief Returns the ID of connected screen by checking the HDMI + * (adv7533 component) ID or LCD DSI (via TS ID) ID. + * @retval LCD ID + */ +static uint16_t LCD_IO_GetID(void) +{ +#if defined(USE_LCD_HDMI) + HDMI_IO_Init(); + + HDMI_IO_Delay(120); + + if(ADV7533_ID == adv7533_drv.ReadID(ADV7533_CEC_DSI_I2C_ADDR)) + { + return ADV7533_ID; + } + else if(((HDMI_IO_Read(LCD_DSI_ADDRESS, LCD_DSI_ID_REG) == LCD_DSI_ID)) || \ + (HDMI_IO_Read(LCD_DSI_ADDRESS_A02, LCD_DSI_ID_REG) == LCD_DSI_ID)) + { + return LCD_DSI_ID; + } + else + { + return 0; + } +#else + return LCD_DSI_ID; +#endif /* USE_LCD_HDMI */ +} + +/******************************************************************************* + LTDC, DMA2D and DSI BSP Routines +*******************************************************************************/ +/** + * @brief De-Initializes the BSP LCD Msp + * Application can surcharge if needed this function implementation. + */ +__weak void BSP_LCD_MspDeInit(void) +{ + /** @brief Disable IRQ of LTDC IP */ + HAL_NVIC_DisableIRQ(LTDC_IRQn); + + /** @brief Disable IRQ of DMA2D IP */ + HAL_NVIC_DisableIRQ(DMA2D_IRQn); + + /** @brief Disable IRQ of DSI IP */ + HAL_NVIC_DisableIRQ(DSI_IRQn); + + /** @brief Force and let in reset state LTDC, DMA2D and DSI Host + Wrapper IPs */ + __HAL_RCC_LTDC_FORCE_RESET(); + __HAL_RCC_DMA2D_FORCE_RESET(); + __HAL_RCC_DSI_FORCE_RESET(); + + /** @brief Disable the LTDC, DMA2D and DSI Host and Wrapper clocks */ + __HAL_RCC_LTDC_CLK_DISABLE(); + __HAL_RCC_DMA2D_CLK_DISABLE(); + __HAL_RCC_DSI_CLK_DISABLE(); +} + +/** + * @brief Initialize the BSP LCD Msp. + * Application can surcharge if needed this function implementation + */ +__weak void BSP_LCD_MspInit(void) +{ + /** @brief Enable the LTDC clock */ + __HAL_RCC_LTDC_CLK_ENABLE(); + + /** @brief Toggle Sw reset of LTDC IP */ + __HAL_RCC_LTDC_FORCE_RESET(); + __HAL_RCC_LTDC_RELEASE_RESET(); + + /** @brief Enable the DMA2D clock */ + __HAL_RCC_DMA2D_CLK_ENABLE(); + + /** @brief Toggle Sw reset of DMA2D IP */ + __HAL_RCC_DMA2D_FORCE_RESET(); + __HAL_RCC_DMA2D_RELEASE_RESET(); + + /** @brief Enable DSI Host and wrapper clocks */ + __HAL_RCC_DSI_CLK_ENABLE(); + + /** @brief Soft Reset the DSI Host and wrapper */ + __HAL_RCC_DSI_FORCE_RESET(); + __HAL_RCC_DSI_RELEASE_RESET(); + + /** @brief NVIC configuration for LTDC interrupt that is now enabled */ + HAL_NVIC_SetPriority(LTDC_IRQn, 3, 0); + HAL_NVIC_EnableIRQ(LTDC_IRQn); + + /** @brief NVIC configuration for DMA2D interrupt that is now enabled */ + HAL_NVIC_SetPriority(DMA2D_IRQn, 3, 0); + HAL_NVIC_EnableIRQ(DMA2D_IRQn); + + /** @brief NVIC configuration for DSI interrupt that is now enabled */ + HAL_NVIC_SetPriority(DSI_IRQn, 3, 0); + HAL_NVIC_EnableIRQ(DSI_IRQn); +} + +/** + * @brief Draws a pixel on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param RGB_Code: Pixel color in ARGB mode (8-8-8-8) + */ +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t RGB_Code) +{ + /* Write data value to all SDRAM memory */ + *(__IO uint32_t*) (hltdc_discovery.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))) = RGB_Code; +} + + +/** + * @brief Draws a character on LCD. + * @param Xpos: Line where to display the character shape + * @param Ypos: Start column address + * @param c: Pointer to the character data + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c) +{ + uint32_t i = 0, j = 0; + uint16_t height, width; + uint8_t offset; + uint8_t *pchar; + uint32_t line; + + height = DrawProp[ActiveLayer].pFont->Height; + width = DrawProp[ActiveLayer].pFont->Width; + + offset = 8 *((width + 7)/8) - width ; + + for(i = 0; i < height; i++) + { + pchar = ((uint8_t *)c + (width + 7)/8 * i); + + switch(((width + 7)/8)) + { + + case 1: + line = pchar[0]; + break; + + case 2: + line = (pchar[0]<< 8) | pchar[1]; + break; + + case 3: + default: + line = (pchar[0]<< 16) | (pchar[1]<< 8) | pchar[2]; + break; + } + + for (j = 0; j < width; j++) + { + if(line & (1 << (width- j + offset- 1))) + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp[ActiveLayer].TextColor); + } + else + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp[ActiveLayer].BackColor); + } + } + Ypos++; + } +} + +/** + * @brief Fills a triangle (between 3 points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @param x3: Point 3 X position + * @param y3: Point 3 Y position + */ +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + numadd = deltay; + numpixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + numadd = deltax; + numpixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= numpixels; curpixel++) + { + BSP_LCD_DrawLine(x, y, x3, y3); + + num += numadd; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Fills a buffer. + * @param LayerIndex: Layer index + * @param pDst: Pointer to destination buffer + * @param xSize: Buffer width + * @param ySize: Buffer height + * @param OffLine: Offset + * @param ColorIndex: Color index + */ +static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex) +{ + /* Register to memory mode with ARGB8888 as color Mode */ + hdma2d_discovery.Init.Mode = DMA2D_R2M; + hdma2d_discovery.Init.ColorMode = DMA2D_OUTPUT_ARGB8888; + hdma2d_discovery.Init.OutputOffset = OffLine; + + hdma2d_discovery.Instance = DMA2D; + + /* DMA2D Initialization */ + if(HAL_DMA2D_Init(&hdma2d_discovery) == HAL_OK) + { + if(HAL_DMA2D_ConfigLayer(&hdma2d_discovery, LayerIndex) == HAL_OK) + { + if (HAL_DMA2D_Start(&hdma2d_discovery, ColorIndex, (uint32_t)pDst, xSize, ySize) == HAL_OK) + { + /* Polling For DMA transfer */ + HAL_DMA2D_PollForTransfer(&hdma2d_discovery, 10); + } + } + } +} + +/** + * @brief Converts a line to an ARGB8888 pixel format. + * @param pSrc: Pointer to source buffer + * @param pDst: Output color + * @param xSize: Buffer width + * @param ColorMode: Input color mode + */ +static void LL_ConvertLineToARGB8888(void *pSrc, void *pDst, uint32_t xSize, uint32_t ColorMode) +{ + /* Configure the DMA2D Mode, Color Mode and output offset */ + hdma2d_discovery.Init.Mode = DMA2D_M2M_PFC; + hdma2d_discovery.Init.ColorMode = DMA2D_OUTPUT_ARGB8888; + hdma2d_discovery.Init.OutputOffset = 0; + + /* Foreground Configuration */ + hdma2d_discovery.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; + hdma2d_discovery.LayerCfg[1].InputAlpha = 0xFF; + hdma2d_discovery.LayerCfg[1].InputColorMode = ColorMode; + hdma2d_discovery.LayerCfg[1].InputOffset = 0; + + hdma2d_discovery.Instance = DMA2D; + + /* DMA2D Initialization */ + if(HAL_DMA2D_Init(&hdma2d_discovery) == HAL_OK) + { + if(HAL_DMA2D_ConfigLayer(&hdma2d_discovery, 1) == HAL_OK) + { + if (HAL_DMA2D_Start(&hdma2d_discovery, (uint32_t)pSrc, (uint32_t)pDst, xSize, 1) == HAL_OK) + { + /* Polling For DMA transfer */ + HAL_DMA2D_PollForTransfer(&hdma2d_discovery, 10); + } + } + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_lcd.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_lcd.h new file mode 100644 index 00000000..8b554313 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_lcd.h @@ -0,0 +1,414 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_lcd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32469i_discovery_lcd.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_DISCOVERY_LCD_H +#define __STM32F769I_DISCOVERY_LCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include LCD component Driver */ + +/* Include OTM8009A LCD Driver IC driver code */ +#include "../Components/otm8009a/otm8009a.h" +/* Include ADV7533 HDMI Driver IC driver code */ +#include "../Components/adv7533/adv7533.h" + +/* Include SDRAM Driver */ +#include "stm32f769i_discovery_sdram.h" +#include "stm32f769i_discovery.h" + +#include "../../../Utilities/Fonts/fonts.h" + +#include /* use of memset() */ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY_LCD + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_LCD_Exported_Constants STM32F769I DISCOVERY LCD Exported Constants + * @{ + */ +#define BSP_LCD_DMA2D_IRQHandler DMA2D_IRQHandler +#define BSP_LCD_DSI_IRQHandler DSI_IRQHandler +#define BSP_LCD_LTDC_IRQHandler LTDC_IRQHandler +#define BSP_LCD_LTDC_ER_IRQHandler LTDC_ER_IRQHandler + + +#define LCD_LayerCfgTypeDef LTDC_LayerCfgTypeDef +/** + * @brief LCD FB_StartAddress + */ +#define LCD_FB_START_ADDRESS ((uint32_t)0xC0000000) + +/** @brief Maximum number of LTDC layers + */ +#define LTDC_MAX_LAYER_NUMBER ((uint32_t) 2) + +/** @brief LTDC Background layer index + */ +#define LTDC_ACTIVE_LAYER_BACKGROUND ((uint32_t) 0) + +/** @brief LTDC Foreground layer index + */ +#define LTDC_ACTIVE_LAYER_FOREGROUND ((uint32_t) 1) + +/** @brief Number of LTDC layers + */ +#define LTDC_NB_OF_LAYERS ((uint32_t) 2) + +/** @brief LTDC Default used layer index + */ +#define LTDC_DEFAULT_ACTIVE_LAYER LTDC_ACTIVE_LAYER_FOREGROUND + +/** + * @brief LCD status structure definition + */ +#define LCD_OK 0x00 +#define LCD_ERROR 0x01 +#define LCD_TIMEOUT 0x02 + +/** + * @brief LCD Display OTM8009A DSI Virtual Channel ID + */ +#define LCD_OTM8009A_ID ((uint32_t) 0) + +/** + * @brief HDMI ADV7533 DSI Virtual Channel ID + */ +#define HDMI_ADV7533_ID ((uint32_t) 0) + +/** + * @brief HDMI Foramt + */ +#define HDMI_FORMAT_720_480 ((uint8_t) 0x00) /*720_480 format choice of HDMI display */ +#define HDMI_FORMAT_720_576 ((uint8_t) 0x01) /*720_576 format choice of HDMI display*/ + +/** + * @brief LCD color definitions values + * in ARGB8888 format. + */ + +/** @brief Blue value in ARGB8888 format + */ +#define LCD_COLOR_BLUE ((uint32_t) 0xFF0000FF) + +/** @brief Green value in ARGB8888 format + */ +#define LCD_COLOR_GREEN ((uint32_t) 0xFF00FF00) + +/** @brief Red value in ARGB8888 format + */ +#define LCD_COLOR_RED ((uint32_t) 0xFFFF0000) + +/** @brief Cyan value in ARGB8888 format + */ +#define LCD_COLOR_CYAN ((uint32_t) 0xFF00FFFF) + +/** @brief Magenta value in ARGB8888 format + */ +#define LCD_COLOR_MAGENTA ((uint32_t) 0xFFFF00FF) + +/** @brief Yellow value in ARGB8888 format + */ +#define LCD_COLOR_YELLOW ((uint32_t) 0xFFFFFF00) + +/** @brief Light Blue value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTBLUE ((uint32_t) 0xFF8080FF) + +/** @brief Light Green value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTGREEN ((uint32_t) 0xFF80FF80) + +/** @brief Light Red value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTRED ((uint32_t) 0xFFFF8080) + +/** @brief Light Cyan value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTCYAN ((uint32_t) 0xFF80FFFF) + +/** @brief Light Magenta value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTMAGENTA ((uint32_t) 0xFFFF80FF) + +/** @brief Light Yellow value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTYELLOW ((uint32_t) 0xFFFFFF80) + +/** @brief Dark Blue value in ARGB8888 format + */ +#define LCD_COLOR_DARKBLUE ((uint32_t) 0xFF000080) + +/** @brief Light Dark Green value in ARGB8888 format + */ +#define LCD_COLOR_DARKGREEN ((uint32_t) 0xFF008000) + +/** @brief Light Dark Red value in ARGB8888 format + */ +#define LCD_COLOR_DARKRED ((uint32_t) 0xFF800000) + +/** @brief Dark Cyan value in ARGB8888 format + */ +#define LCD_COLOR_DARKCYAN ((uint32_t) 0xFF008080) + +/** @brief Dark Magenta value in ARGB8888 format + */ +#define LCD_COLOR_DARKMAGENTA ((uint32_t) 0xFF800080) + +/** @brief Dark Yellow value in ARGB8888 format + */ +#define LCD_COLOR_DARKYELLOW ((uint32_t) 0xFF808000) + +/** @brief White value in ARGB8888 format + */ +#define LCD_COLOR_WHITE ((uint32_t) 0xFFFFFFFF) + +/** @brief Light Gray value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTGRAY ((uint32_t) 0xFFD3D3D3) + +/** @brief Gray value in ARGB8888 format + */ +#define LCD_COLOR_GRAY ((uint32_t) 0xFF808080) + +/** @brief Dark Gray value in ARGB8888 format + */ +#define LCD_COLOR_DARKGRAY ((uint32_t) 0xFF404040) + +/** @brief Black value in ARGB8888 format + */ +#define LCD_COLOR_BLACK ((uint32_t) 0xFF000000) + +/** @brief Brown value in ARGB8888 format + */ +#define LCD_COLOR_BROWN ((uint32_t) 0xFFA52A2A) + +/** @brief Orange value in ARGB8888 format + */ +#define LCD_COLOR_ORANGE ((uint32_t) 0xFFFFA500) + +/** @brief Transparent value in ARGB8888 format + */ +#define LCD_COLOR_TRANSPARENT ((uint32_t) 0xFF000000) + +/** + * @brief LCD default font + */ +#define LCD_DEFAULT_FONT Font24 + +/** + * @brief Possible values of + * pixel data format (ie color coding) transmitted on DSI Data lane in DSI packets + */ + +#define LCD_DSI_PIXEL_DATA_FMT_RBG888 DSI_RGB888 /*!< DSI packet pixel format chosen is RGB888 : 24 bpp */ +#define LCD_DSI_PIXEL_DATA_FMT_RBG565 DSI_RGB565 /*!< DSI packet pixel format chosen is RGB565 : 16 bpp */ + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LCD_Exported_Types STM32F769I DISCOVERY LCD Exported Types + * @{ + */ + +/** +* @brief LCD Drawing main properties +*/ +typedef struct +{ + uint32_t TextColor; /*!< Specifies the color of text */ + uint32_t BackColor; /*!< Specifies the background color below the text */ + sFONT *pFont; /*!< Specifies the font used for the text */ + +} LCD_DrawPropTypeDef; + +/** + * @brief LCD Drawing point (pixel) geometric definition + */ +typedef struct +{ + int16_t X; /*!< geometric X position of drawing */ + int16_t Y; /*!< geometric Y position of drawing */ + +} Point; + +/** + * @brief Pointer on LCD Drawing point (pixel) geometric definition + */ +typedef Point * pPoint; + +/** + * @brief LCD drawing Line alignment mode definitions + */ +typedef enum +{ + CENTER_MODE = 0x01, /*!< Center mode */ + RIGHT_MODE = 0x02, /*!< Right mode */ + LEFT_MODE = 0x03 /*!< Left mode */ + +} Text_AlignModeTypdef; + + +/** + * @brief LCD_OrientationTypeDef + * Possible values of Display Orientation + */ +typedef enum +{ + LCD_ORIENTATION_PORTRAIT = 0x00, /*!< Portrait orientation choice of LCD screen */ + LCD_ORIENTATION_LANDSCAPE = 0x01, /*!< Landscape orientation choice of LCD screen */ + LCD_ORIENTATION_INVALID = 0x02 /*!< Invalid orientation choice of LCD screen */ +} LCD_OrientationTypeDef; + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LCD_Exported_Macro STM32F769I DISCOVERY LCD Exported Macro + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY_LCD_Exported_Functions + * @{ + */ +uint8_t BSP_LCD_Init(void); +uint8_t BSP_LCD_InitEx(LCD_OrientationTypeDef orientation); +uint8_t BSP_LCD_HDMIInitEx(uint8_t format); + +void BSP_LCD_MspDeInit(void); +void BSP_LCD_MspInit(void); +void BSP_LCD_Reset(void); + +uint32_t BSP_LCD_GetXSize(void); +uint32_t BSP_LCD_GetYSize(void); +void BSP_LCD_SetXSize(uint32_t imageWidthPixels); +void BSP_LCD_SetYSize(uint32_t imageHeightPixels); + +void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address); +void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency); +void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address); +void BSP_LCD_SetColorKeying(uint32_t LayerIndex, uint32_t RGBValue); +void BSP_LCD_ResetColorKeying(uint32_t LayerIndex); +void BSP_LCD_SetLayerWindow(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); + +void BSP_LCD_SelectLayer(uint32_t LayerIndex); +void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState State); + +void BSP_LCD_SetTextColor(uint32_t Color); +uint32_t BSP_LCD_GetTextColor(void); +void BSP_LCD_SetBackColor(uint32_t Color); +uint32_t BSP_LCD_GetBackColor(void); +void BSP_LCD_SetFont(sFONT *fonts); +sFONT *BSP_LCD_GetFont(void); + +uint32_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos); +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t pixel); +void BSP_LCD_Clear(uint32_t Color); +void BSP_LCD_ClearStringLine(uint32_t Line); +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr); +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode); +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii); + +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius); +void BSP_LCD_DrawBitmap(uint32_t Xpos, uint32_t Ypos, uint8_t *pbmp); + +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius); + +void BSP_LCD_DisplayOn(void); +void BSP_LCD_DisplayOff(void); +void BSP_LCD_SetBrightness(uint8_t BrightnessValue); + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_LCD_Exported_Variables STM32F769I DISCOVERY LCD Exported Variables + * @{ + */ + +/* @brief DMA2D handle variable */ +extern DMA2D_HandleTypeDef hdma2d_discovery; + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_DISCOVERY_LCD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_qspi.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_qspi.c new file mode 100644 index 00000000..7baf3560 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_qspi.c @@ -0,0 +1,1182 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_qspi.c + * @author MCD Application Team + * @brief This file includes a standard driver for the MX25L512 QSPI + * memory mounted on STM32F769I-Discovery board. + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + (#) This driver is used to drive the MX25L512 QSPI external + memory mounted on STM32F769I-Discovery board. + + (#) This driver need a specific component driver (MX25L51245G) to be included with. + + (#) Initialization steps: + (++) Initialize the QPSI external memory using the BSP_QSPI_Init() function. This + function includes the MSP layer hardware resources initialization and the + QSPI interface with the external memory. + + (#) QSPI memory operations + (++) QSPI memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_QSPI_Read()/BSP_QSPI_Write(). + (++) The function BSP_QSPI_GetInfo() returns the configuration of the QSPI memory. + (see the QSPI memory data sheet) + (++) Perform erase block operation using the function BSP_QSPI_Erase_Block() and by + specifying the block address. You can perform an erase operation of the whole + chip by calling the function BSP_QSPI_Erase_Chip(). + (++) The function BSP_QSPI_GetStatus() returns the current status of the QSPI memory. + (see the QSPI memory data sheet) + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_qspi.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- mx25l512.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_discovery_qspi.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_QSPI STM32F769I_DISCOVERY QSPI + * @{ + */ + + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup STM32F769I_DISCOVERY_QSPI_Private_Variables STM32F769I_DISCOVERY QSPI Private Variables + * @{ + */ +QSPI_HandleTypeDef QSPIHandle; + +/** + * @} + */ + + + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup STM32F769I_DISCOVERY_QSPI_Private_Functions STM32F769I_DISCOVERY QSPI Private Functions + * @{ + */ +static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_EnterMemory_QPI(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_ExitMemory_QPI(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_OutDrvStrengthCfg(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_AutoPollingMemReady (QSPI_HandleTypeDef *hqspi, uint32_t Timeout); + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_QSPI_Exported_Functions STM32F769I_DISCOVERY QSPI Exported Functions + * @{ + */ + +/** + * @brief Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Init(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level initialization */ + BSP_QSPI_MspInit(&QSPIHandle, NULL); + + /* QSPI initialization */ + /* QSPI freq = SYSCLK /(1 + ClockPrescaler) = 216 MHz/(1+1) = 108 Mhz */ + QSPIHandle.Init.ClockPrescaler = 1; /* QSPI freq = 216 MHz/(1+1) = 108 Mhz */ + QSPIHandle.Init.FifoThreshold = 16; + QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; + QSPIHandle.Init.FlashSize = POSITION_VAL(MX25L512_FLASH_SIZE) - 1; + QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_4_CYCLE; /* Min 30ns for nonRead */ + QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; + QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1; + QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE; + + if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* QSPI memory reset */ + if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Put QSPI memory in QPI mode */ + if( QSPI_EnterMemory_QPI( &QSPIHandle )!=QSPI_OK ) + { + return QSPI_NOT_SUPPORTED; + } + + /* Set the QSPI memory in 4-bytes address mode */ + if (QSPI_EnterFourBytesAddress(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Configuration of the dummy cycles on QSPI memory side */ + if (QSPI_DummyCyclesCfg(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Configuration of the Output driver strength on memory side */ + if( QSPI_OutDrvStrengthCfg( &QSPIHandle ) != QSPI_OK ) + { + return QSPI_NOT_SUPPORTED; + } + + return QSPI_OK; +} + +/** + * @brief De-Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_DeInit(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Put QSPI memory in SPI mode */ + if( QSPI_ExitMemory_QPI(&QSPIHandle )!=QSPI_OK ) + { + return QSPI_NOT_SUPPORTED; + } + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level De-initialization */ + BSP_QSPI_MspDeInit(&QSPIHandle, NULL); + + return QSPI_OK; +} + +/** + * @brief Reads an amount of data from the QSPI memory. + * @param pData: Pointer to data to be read + * @param ReadAddr: Read start address + * @param Size: Size of data to read + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the read command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = QPI_READ_4_BYTE_ADDR_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.Address = ReadAddr; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = MX25L512_DUMMY_CYCLES_READ_QUAD_IO; + s_command.NbData = Size; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Set S# timing for Read command */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_1_CYCLE); + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Restore S# timing for nonRead commands */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_4_CYCLE); + + return QSPI_OK; +} + +/** + * @brief Writes an amount of data to the QSPI memory. + * @param pData: Pointer to data to be written + * @param WriteAddr: Write start address + * @param Size: Size of data to write + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + uint32_t end_addr, current_size, current_addr; + + /* Calculation of the size between the write address and the end of the page */ + current_size = MX25L512_PAGE_SIZE - (WriteAddr % MX25L512_PAGE_SIZE); + + /* Check if the size of the data is less than the remaining place in the page */ + if (current_size > Size) + { + current_size = Size; + } + + /* Initialize the address variables */ + current_addr = WriteAddr; + end_addr = WriteAddr + Size; + + /* Initialize the program command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = QPI_PAGE_PROG_4_BYTE_ADDR_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Perform the write page by page */ + do + { + s_command.Address = current_addr; + s_command.NbData = current_size; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of program */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update the address and size variables for next page programming */ + current_addr += current_size; + pData += current_size; + current_size = ((current_addr + MX25L512_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : MX25L512_PAGE_SIZE; + } while (current_addr < end_addr); + + return QSPI_OK; +} + +/** + * @brief Erases the specified block of the QSPI memory. + * @param BlockAddress: Block address to erase + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = SUBSECTOR_ERASE_4_BYTE_ADDR_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.Address = BlockAddress; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, MX25L512_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Erases the entire QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Chip(void) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = BULK_ERASE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, MX25L512_BULK_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Reads current status of the QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetStatus(void) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg; + + /* Initialize the read flag status register command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Check the value of the register*/ + if ((reg & MX25L512_SR_WIP) == 0) + { + return QSPI_OK; + } + else + { + return QSPI_BUSY; + } +} + +/** + * @brief Return the configuration of the QSPI memory. + * @param pInfo: pointer on the configuration structure + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetInfo(QSPI_Info* pInfo) +{ + /* Configure the structure with the memory configuration */ + pInfo->FlashSize = MX25L512_FLASH_SIZE; + pInfo->EraseSectorSize = MX25L512_SUBSECTOR_SIZE; + pInfo->EraseSectorsNumber = (MX25L512_FLASH_SIZE/MX25L512_SUBSECTOR_SIZE); + pInfo->ProgPageSize = MX25L512_PAGE_SIZE; + pInfo->ProgPagesNumber = (MX25L512_FLASH_SIZE/MX25L512_PAGE_SIZE); + + return QSPI_OK; +} + +/** + * @brief Configure the QSPI in memory-mapped mode + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_EnableMemoryMappedMode(void) +{ + QSPI_CommandTypeDef s_command; + QSPI_MemoryMappedTypeDef s_mem_mapped_cfg; + + /* Configure the command for the read instruction */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = QPI_READ_4_BYTE_ADDR_CMD; + s_command.AddressMode = QSPI_ADDRESS_4_LINES; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = MX25L512_DUMMY_CYCLES_READ_QUAD_IO; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the memory mapped mode */ + s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; + s_mem_mapped_cfg.TimeOutPeriod = 0; + + if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @} + */ + +/** @addtogroup STM32F769I_DISCOVERY_QSPI_Private_Functions + * @{ + */ + +/** + * @brief QSPI MSP Initialization + * This function configures the hardware resources used in this example: + * - Peripheral's clock enable + * - Peripheral's GPIO Configuration + * - NVIC configuration for QSPI interrupt + * @retval None + */ +__weak void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /*##-1- Enable peripherals and GPIO Clocks #################################*/ + /* Enable the QuadSPI memory interface clock */ + QSPI_CLK_ENABLE(); + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + /* Enable GPIO clocks */ + QSPI_CS_GPIO_CLK_ENABLE(); + QSPI_CLK_GPIO_CLK_ENABLE(); + QSPI_D0_GPIO_CLK_ENABLE(); + QSPI_D1_GPIO_CLK_ENABLE(); + QSPI_D2_GPIO_CLK_ENABLE(); + QSPI_D3_GPIO_CLK_ENABLE(); + + /*##-2- Configure peripheral GPIO ##########################################*/ + /* QSPI CS GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CS_PIN; + gpio_init_structure.Alternate = QSPI_CS_PIN_AF; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &gpio_init_structure); + /* QSPI CLK GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CLK_PIN; + gpio_init_structure.Alternate = QSPI_CLK_PIN_AF; + gpio_init_structure.Pull = GPIO_NOPULL; + HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &gpio_init_structure); + /* QSPI D0 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D0_PIN; + gpio_init_structure.Alternate = QSPI_D0_PIN_AF; + HAL_GPIO_Init(QSPI_D0_GPIO_PORT, &gpio_init_structure); + /* QSPI D1 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D1_PIN; + gpio_init_structure.Alternate = QSPI_D1_PIN_AF; + HAL_GPIO_Init(QSPI_D1_GPIO_PORT, &gpio_init_structure); + /* QSPI D2 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D2_PIN; + gpio_init_structure.Alternate = QSPI_D2_PIN_AF; + HAL_GPIO_Init(QSPI_D2_GPIO_PORT, &gpio_init_structure); + /* QSPI D3 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D3_PIN; + gpio_init_structure.Alternate = QSPI_D3_PIN_AF; + HAL_GPIO_Init(QSPI_D3_GPIO_PORT, &gpio_init_structure); + + /*##-3- Configure the NVIC for QSPI #########################################*/ + /* NVIC configuration for QSPI interrupt */ + HAL_NVIC_SetPriority(QUADSPI_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(QUADSPI_IRQn); +} + +/** + * @brief QSPI MSP De-Initialization + * This function frees the hardware resources used in this example: + * - Disable the Peripheral's clock + * - Revert GPIO and NVIC configuration to their default state + * @retval None + */ +__weak void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + /*##-1- Disable the NVIC for QSPI ###########################################*/ + HAL_NVIC_DisableIRQ(QUADSPI_IRQn); + + /*##-2- Disable peripherals and GPIO Clocks ################################*/ + /* De-Configure QSPI pins */ + HAL_GPIO_DeInit(QSPI_CS_GPIO_PORT, QSPI_CS_PIN); + HAL_GPIO_DeInit(QSPI_CLK_GPIO_PORT, QSPI_CLK_PIN); + HAL_GPIO_DeInit(QSPI_D0_GPIO_PORT, QSPI_D0_PIN); + HAL_GPIO_DeInit(QSPI_D1_GPIO_PORT, QSPI_D1_PIN); + HAL_GPIO_DeInit(QSPI_D2_GPIO_PORT, QSPI_D2_PIN); + HAL_GPIO_DeInit(QSPI_D3_GPIO_PORT, QSPI_D3_PIN); + + /*##-3- Reset peripherals ##################################################*/ + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + + /* Disable the QuadSPI memory interface clock */ + QSPI_CLK_DISABLE(); +} + +/** + * @brief This function reset the QSPI memory. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + uint8_t reg; + + /* Send command RESET command in QPI mode (QUAD I/Os) */ + /* Initialize the reset enable command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = RESET_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + /* Send the reset memory command */ + s_command.Instruction = RESET_MEMORY_CMD; + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Send command RESET command in SPI mode */ + /* Initialize the reset enable command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = RESET_ENABLE_CMD; + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + /* Send the reset memory command */ + s_command.Instruction = RESET_MEMORY_CMD; + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* After reset CMD, 1000ms requested if QSPI memory SWReset occured during full chip erase operation */ + HAL_Delay( 1000 ); + + /* Configure automatic polling mode to wait the WIP bit=0 */ + s_config.Match = 0; + s_config.Mask = MX25L512_SR_WIP; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_1_LINE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Initialize the reading of status register */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations, command in 1 bit */ + /* Enable write operations */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = WRITE_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for write enabling */ + s_config.Match = MX25L512_SR_WREN; + s_config.Mask = MX25L512_SR_WREN; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_1_LINE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Update the configuration register with new dummy cycles */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = WRITE_STATUS_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable the Quad IO on the QSPI memory (Non-volatile bit) */ + reg |= MX25L512_SR_QUADEN; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* 40ms Write Status/Configuration Register Cycle Time */ + HAL_Delay( 40 ); + + return QSPI_OK; +} + +/** + * @brief This function set the QSPI memory in 4-byte address mode + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the command */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = ENTER_4_BYTE_ADDR_MODE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(hqspi) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait the memory is ready */ + if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function configure the dummy cycles on memory side. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg[2]; + + /* Initialize the reading of status register */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Initialize the reading of configuration register */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, &(reg[1]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations */ + if (QSPI_WriteEnable(hqspi) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update the configuration register with new dummy cycles */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = WRITE_STATUS_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 2; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* MX25L512_DUMMY_CYCLES_READ_QUAD = 3 for 10 cycles in QPI mode */ + MODIFY_REG( reg[1], MX25L512_CR_NB_DUMMY, (MX25L512_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(MX25L512_CR_NB_DUMMY))); + + /* Configure the write volatile configuration register command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(hqspi, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* 40ms Write Status/Configuration Register Cycle Time */ + HAL_Delay( 40 ); + + return QSPI_OK; +} + +/** + * @brief This function put QSPI memory in QPI mode (quad I/O). + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_EnterMemory_QPI( QSPI_HandleTypeDef *hqspi ) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Initialize the QPI enable command */ + /* QSPI memory is supported to be in SPI mode, so CMD on 1 LINE */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = ENTER_QUAD_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait the QUADEN bit=1 and WIP bit=0 */ + s_config.Match = MX25L512_SR_QUADEN; + s_config.Mask = MX25L512_SR_QUADEN|MX25L512_SR_WIP; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_4_LINES; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function put QSPI memory in SPI mode. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_ExitMemory_QPI( QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the QPI enable command */ + /* QSPI memory is supported to be in QPI mode, so CMD on 4 LINES */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = EXIT_QUAD_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function configure the Output driver strength on memory side. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_OutDrvStrengthCfg( QSPI_HandleTypeDef *hqspi ) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg[2]; + + /* Initialize the reading of status register */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Initialize the reading of configuration register */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, &(reg[1]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update the configuration register with new output driver strength */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = WRITE_STATUS_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.NbData = 2; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Set Output Strength of the QSPI memory 15 ohms */ + MODIFY_REG( reg[1], MX25L512_CR_ODS, (MX25L512_CR_ODS_15 << POSITION_VAL(MX25L512_CR_ODS))); + + /* Configure the write volatile configuration register command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(hqspi, &(reg[0]), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function send a Write Enable and wait it is effective. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Enable write operations */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = WRITE_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for write enabling */ + s_config.Match = MX25L512_SR_WREN; + s_config.Mask = MX25L512_SR_WREN; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_4_LINES; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function read the SR of the memory and wait the EOP. + * @param hqspi: QSPI handle + * @param Timeout + * @retval None + */ +static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Configure automatic polling mode to wait for memory ready */ + s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + s_config.Match = 0; + s_config.Mask = MX25L512_SR_WIP; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, Timeout) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_qspi.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_qspi.h new file mode 100644 index 00000000..7e53e637 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_qspi.h @@ -0,0 +1,175 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_qspi.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_discovery_qspi.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_DISCOVERY_QSPI_H +#define __STM32F769I_DISCOVERY_QSPI_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" +#include "../Components/mx25l512/mx25l512.h" + +/** @addtogroup STM32F769I_DISCOVERY_QSPI + * @{ + */ + + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup STM32F769I_DISCOVERY_QSPI_Exported_Constants STM32F769I_DISCOVERY_QSPI Exported Constants + * @{ + */ +/* QSPI Error codes */ +#define QSPI_OK ((uint8_t)0x00) +#define QSPI_ERROR ((uint8_t)0x01) +#define QSPI_BUSY ((uint8_t)0x02) +#define QSPI_NOT_SUPPORTED ((uint8_t)0x04) +#define QSPI_SUSPENDED ((uint8_t)0x08) + + +/* Definition for QSPI clock resources */ +#define QSPI_CLK_ENABLE() __HAL_RCC_QSPI_CLK_ENABLE() +#define QSPI_CLK_DISABLE() __HAL_RCC_QSPI_CLK_DISABLE() +#define QSPI_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_CLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_D0_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define QSPI_D1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define QSPI_D2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() +#define QSPI_D3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() + +#define QSPI_FORCE_RESET() __HAL_RCC_QSPI_FORCE_RESET() +#define QSPI_RELEASE_RESET() __HAL_RCC_QSPI_RELEASE_RESET() + +/* Definition for QSPI Pins */ +/* QSPI_CS */ +#define QSPI_CS_PIN GPIO_PIN_6 +#define QSPI_CS_GPIO_PORT GPIOB +#define QSPI_CS_PIN_AF GPIO_AF10_QUADSPI +/* QSPI_CLK */ +#define QSPI_CLK_PIN GPIO_PIN_2 +#define QSPI_CLK_GPIO_PORT GPIOB +#define QSPI_CLK_PIN_AF GPIO_AF9_QUADSPI +/* QSPI_D0 */ +#define QSPI_D0_PIN GPIO_PIN_9 +#define QSPI_D0_GPIO_PORT GPIOC +#define QSPI_D0_PIN_AF GPIO_AF9_QUADSPI +/* QSPI_D1 */ +#define QSPI_D1_PIN GPIO_PIN_10 +#define QSPI_D1_GPIO_PORT GPIOC +#define QSPI_D1_PIN_AF GPIO_AF9_QUADSPI +/* QSPI_D2 */ +#define QSPI_D2_PIN GPIO_PIN_2 +#define QSPI_D2_GPIO_PORT GPIOE +#define QSPI_D2_PIN_AF GPIO_AF9_QUADSPI +/* QSPI_D3 */ +#define QSPI_D3_PIN GPIO_PIN_13 +#define QSPI_D3_GPIO_PORT GPIOD +#define QSPI_D3_PIN_AF GPIO_AF9_QUADSPI + +/** + * @} + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup STM32F769I_DISCOVERY_QSPI_Exported_Types STM32F769I_DISCOVERY_QSPI Exported Types + * @{ + */ +/* QSPI Info */ +typedef struct { + uint32_t FlashSize; /*!< Size of the flash */ + uint32_t EraseSectorSize; /*!< Size of sectors for the erase operation */ + uint32_t EraseSectorsNumber; /*!< Number of sectors for the erase operation */ + uint32_t ProgPageSize; /*!< Size of pages for the program operation */ + uint32_t ProgPagesNumber; /*!< Number of pages for the program operation */ +} QSPI_Info; + +/** + * @} + */ + + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup STM32F769I_DISCOVERY_QSPI_Exported_Functions + * @{ + */ +uint8_t BSP_QSPI_Init (void); +uint8_t BSP_QSPI_DeInit (void); +uint8_t BSP_QSPI_Read (uint8_t* pData, uint32_t ReadAddr, uint32_t Size); +uint8_t BSP_QSPI_Write (uint8_t* pData, uint32_t WriteAddr, uint32_t Size); +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress); +uint8_t BSP_QSPI_Erase_Chip (void); +uint8_t BSP_QSPI_GetStatus (void); +uint8_t BSP_QSPI_GetInfo (QSPI_Info* pInfo); +uint8_t BSP_QSPI_EnableMemoryMappedMode(void); + +/* These functions can be modified in case the current settings + need to be changed for specific application needs */ +void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params); +void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_DISCOVERY_QSPI_H */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sd.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sd.c new file mode 100644 index 00000000..5ea81c4b --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sd.c @@ -0,0 +1,611 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_sd.c + * @author MCD Application Team + * @brief This file includes the uSD card driver mounted on STM32F769I-Discovery + * board. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* File Info : ----------------------------------------------------------------- + User NOTES +1. How To use this driver: +-------------------------- + - This driver is used to drive the micro SD external card mounted on STM32F769I-Discovery + board. + - This driver does not need a specific component driver for the micro SD device + to be included with. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the micro SD card using the BSP_SD_Init() function. This + function includes the MSP layer hardware resources initialization and the + SDIO interface configuration to interface with the external micro SD. It + also includes the micro SD initialization sequence. + o To check the SD card presence you can use the function BSP_SD_IsDetected() which + returns the detection status + o If SD presence detection interrupt mode is desired, you must configure the + SD detection interrupt mode by calling the function BSP_SD_ITConfig(). The interrupt + is generated as an external interrupt whenever the micro SD card is + plugged/unplugged in/from the discovery board. + o The function BSP_SD_GetCardInfo() is used to get the micro SD card information + which is stored in the structure "HAL_SD_CardInfoTypedef". + + + Micro SD card operations + o The micro SD card can be accessed with read/write block(s) operations once + it is reay for access. The access cand be performed whether using the polling + mode by calling the functions BSP_SD_ReadBlocks()/BSP_SD_WriteBlocks(), or by DMA + transfer using the functions BSP_SD_ReadBlocks_DMA()/BSP_SD_WriteBlocks_DMA() + o The DMA transfer complete is used with interrupt mode. Once the SD transfer + is complete, the SD interrupt is handeled using the function BSP_SD_IRQHandler(), + the DMA Tx/Rx transfer complete are handeled using the functions + BSP_SD_DMA_Tx_IRQHandler()/BSP_SD_DMA_Rx_IRQHandler(). The corresponding user callbacks + are implemented by the user at application level. + o The SD erase block(s) is performed using the function BSP_SD_Erase() with specifying + the number of blocks to erase. + o The SD runtime status is returned when calling the function BSP_SD_GetCardState(). + +------------------------------------------------------------------------------*/ + +/* Dependencies +- stm32f7xx_hal_sd.c +- stm32f7xx_ll_sdmmc.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_discovery_sd.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_SD STM32F769I_DISCOVERY SD + * @{ + */ + + +/** @defgroup STM32F769I_DISCOVERY_SD_Private_TypesDefinitions STM32F769I Discovery Sd Private TypesDef + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SD_Private_Defines STM32F769I Discovery Sd Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SD_Private_Macros STM32F769I Discovery Sd Private Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SD_Private_Variables STM32F769I Discovery Sd Private Variables + * @{ + */ +SD_HandleTypeDef uSdHandle; + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SD_Private_FunctionPrototypes STM32F769I Discovery Sd Private Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SD_Private_Functions STM32F769I Discovery Sd Private Functions + * @{ + */ + +/** + * @brief Initializes the SD card device. + * @retval SD status + */ +uint8_t BSP_SD_Init(void) +{ + uint8_t sd_state = MSD_OK; + + /* PLLSAI is dedicated to LCD periph. Do not use it to get 48MHz*/ + + /* uSD device interface configuration */ + uSdHandle.Instance = SDMMC2; + uSdHandle.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + uSdHandle.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE; + uSdHandle.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; + uSdHandle.Init.BusWide = SDMMC_BUS_WIDE_1B; + uSdHandle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + uSdHandle.Init.ClockDiv = SDMMC_TRANSFER_CLK_DIV; + + /* Msp SD Detect pin initialization */ + BSP_SD_Detect_MspInit(&uSdHandle, NULL); + if(BSP_SD_IsDetected() != SD_PRESENT) /* Check if SD card is present */ + { + return MSD_ERROR_SD_NOT_PRESENT; + } + + /* Msp SD initialization */ + BSP_SD_MspInit(&uSdHandle, NULL); + + /* HAL SD initialization */ + if(HAL_SD_Init(&uSdHandle) != HAL_OK) + { + sd_state = MSD_ERROR; + } + + /* Configure SD Bus width */ + if(sd_state == MSD_OK) + { + /* Enable wide operation */ + if(HAL_SD_ConfigWideBusOperation(&uSdHandle, SDMMC_BUS_WIDE_4B) != HAL_OK) + { + sd_state = MSD_ERROR; + } + else + { + sd_state = MSD_OK; + } + } + return sd_state; +} + +/** + * @brief DeInitializes the SD card device. + * @retval SD status + */ +uint8_t BSP_SD_DeInit(void) +{ + uint8_t sd_state = MSD_OK; + + uSdHandle.Instance = SDMMC2; + + /* HAL SD deinitialization */ + if(HAL_SD_DeInit(&uSdHandle) != HAL_OK) + { + sd_state = MSD_ERROR; + } + + /* Msp SD deinitialization */ + uSdHandle.Instance = SDMMC2; + BSP_SD_MspDeInit(&uSdHandle, NULL); + + return sd_state; +} + +/** + * @brief Configures Interrupt mode for SD detection pin. + * @retval Returns 0 + */ +uint8_t BSP_SD_ITConfig(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Configure Interrupt mode for SD detection pin */ + gpio_init_structure.Pin = SD_DETECT_PIN; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Mode = GPIO_MODE_IT_RISING_FALLING; + HAL_GPIO_Init(SD_DETECT_GPIO_PORT, &gpio_init_structure); + + /* Enable and set SD detect EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(SD_DETECT_EXTI_IRQn), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(SD_DETECT_EXTI_IRQn)); + + return MSD_OK; +} + +/** + * @brief Detects if SD card is correctly plugged in the memory slot or not. + * @retval Returns if SD is detected or not + */ +uint8_t BSP_SD_IsDetected(void) +{ + __IO uint8_t status = SD_PRESENT; + + /* Check SD card detect pin */ + if (HAL_GPIO_ReadPin(SD_DETECT_GPIO_PORT, SD_DETECT_PIN) == GPIO_PIN_SET) + { + status = SD_NOT_PRESENT; + } + + return status; +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @param Timeout: Timeout for read operation + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + if(HAL_SD_ReadBlocks(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks, Timeout) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @param Timeout: Timeout for write operation + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + if(HAL_SD_WriteBlocks(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks, Timeout) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in DMA mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks) +{ + /* Read block(s) in DMA transfer mode */ + if(HAL_SD_ReadBlocks_DMA(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in DMA mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks) +{ + /* Write block(s) in DMA transfer mode */ + if(HAL_SD_WriteBlocks_DMA(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Erases the specified memory area of the given SD card. + * @param StartAddr: Start byte address + * @param EndAddr: End byte address + * @retval SD status + */ +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr) +{ + if(HAL_SD_Erase(&uSdHandle, StartAddr, EndAddr) != HAL_OK) + { + return MSD_ERROR; + } + else + { + return MSD_OK; + } +} + +/** + * @brief Initializes the SD MSP. + * @param hsd: SD handle + * @param Params : pointer on additional configuration parameters, can be NULL. + */ +__weak void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params) +{ + static DMA_HandleTypeDef dma_rx_handle; + static DMA_HandleTypeDef dma_tx_handle; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SDMMC2 clock */ + __HAL_RCC_SDMMC2_CLK_ENABLE(); + + /* Enable DMA2 clocks */ + __DMAx_TxRx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + + /* GPIOB configuration */ + gpio_init_structure.Alternate = GPIO_AF10_SDMMC2; + gpio_init_structure.Pin = GPIO_PIN_3 | GPIO_PIN_4; + HAL_GPIO_Init(GPIOB, &gpio_init_structure); + + /* GPIOD configuration */ + gpio_init_structure.Alternate = GPIO_AF11_SDMMC2; + gpio_init_structure.Pin = GPIO_PIN_6 | GPIO_PIN_7; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_9 | GPIO_PIN_10; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + /* NVIC configuration for SDMMC2 interrupts */ + HAL_NVIC_SetPriority(SDMMC2_IRQn, 0x0E, 0); + HAL_NVIC_EnableIRQ(SDMMC2_IRQn); + + /* Configure DMA Rx parameters */ + dma_rx_handle.Init.Channel = SD_DMAx_Rx_CHANNEL; + dma_rx_handle.Init.Direction = DMA_PERIPH_TO_MEMORY; + dma_rx_handle.Init.PeriphInc = DMA_PINC_DISABLE; + dma_rx_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_rx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_rx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_rx_handle.Init.Mode = DMA_PFCTRL; + dma_rx_handle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + dma_rx_handle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + dma_rx_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_rx_handle.Init.MemBurst = DMA_MBURST_INC4; + dma_rx_handle.Init.PeriphBurst = DMA_PBURST_INC4; + + dma_rx_handle.Instance = SD_DMAx_Rx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsd, hdmarx, dma_rx_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_rx_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_rx_handle); + + /* Configure DMA Tx parameters */ + dma_tx_handle.Init.Channel = SD_DMAx_Tx_CHANNEL; + dma_tx_handle.Init.Direction = DMA_MEMORY_TO_PERIPH; + dma_tx_handle.Init.PeriphInc = DMA_PINC_DISABLE; + dma_tx_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_tx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_tx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_tx_handle.Init.Mode = DMA_PFCTRL; + dma_tx_handle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + dma_tx_handle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + dma_tx_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_tx_handle.Init.MemBurst = DMA_MBURST_INC4; + dma_tx_handle.Init.PeriphBurst = DMA_PBURST_INC4; + + dma_tx_handle.Instance = SD_DMAx_Tx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsd, hdmatx, dma_tx_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_tx_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_tx_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD_DMAx_Rx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SD_DMAx_Rx_IRQn); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD_DMAx_Tx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SD_DMAx_Tx_IRQn); +} + +/** + * @brief Initializes the SD Detect pin MSP. + * @param hsd: SD handle + * @param Params : pointer on additional configuration parameters, can be NULL. + * @retval None + */ +__weak void BSP_SD_Detect_MspInit(SD_HandleTypeDef *hsd, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + SD_DETECT_GPIO_CLK_ENABLE(); + + /* GPIO configuration in input for uSD_Detect signal */ + gpio_init_structure.Pin = SD_DETECT_PIN; + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(SD_DETECT_GPIO_PORT, &gpio_init_structure); +} + +/** + * @brief DeInitializes the SD MSP. + * @param hsd: SD handle + * @param Params : pointer on additional configuration parameters, can be NULL. + */ +__weak void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params) +{ + static DMA_HandleTypeDef dma_rx_handle; + static DMA_HandleTypeDef dma_tx_handle; + + /* Disable NVIC for DMA transfer complete interrupts */ + HAL_NVIC_DisableIRQ(SD_DMAx_Rx_IRQn); + HAL_NVIC_DisableIRQ(SD_DMAx_Tx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_rx_handle.Instance = SD_DMAx_Rx_STREAM; + HAL_DMA_DeInit(&dma_rx_handle); + + /* Deinitialize the stream for new transfer */ + dma_tx_handle.Instance = SD_DMAx_Tx_STREAM; + HAL_DMA_DeInit(&dma_tx_handle); + + /* Disable NVIC for SDIO interrupts */ + HAL_NVIC_DisableIRQ(SDIO_IRQn); + + /* DeInit GPIO pins can be done in the application + (by surcharging this __weak function) */ + + /* Disable SDIO clock */ + __HAL_RCC_SDIO_CLK_DISABLE(); + + /* GPOI pins clock and DMA cloks can be shut down in the applic + by surcgarging this __weak function */ +} + +/** + * @brief Gets the current SD card data status. + * @retval Data transfer state. + * This value can be one of the following values: + * @arg SD_TRANSFER_OK: No data transfer is acting + * @arg SD_TRANSFER_BUSY: Data transfer is acting + */ +uint8_t BSP_SD_GetCardState(void) +{ + return((HAL_SD_GetCardState(&uSdHandle) == HAL_SD_CARD_TRANSFER ) ? SD_TRANSFER_OK : SD_TRANSFER_BUSY); +} + + +/** + * @brief Get SD information about specific SD card. + * @param CardInfo: Pointer to HAL_SD_CardInfoTypedef structure + * @retval None + */ +void BSP_SD_GetCardInfo(HAL_SD_CardInfoTypeDef *CardInfo) +{ + /* Get SD card Information */ + HAL_SD_GetCardInfo(&uSdHandle, CardInfo); +} + +/** + * @brief SD Abort callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_AbortCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_AbortCallback(); +} + +/** + * @brief Tx Transfer completed callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_WriteCpltCallback(); +} + +/** + * @brief Rx Transfer completed callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_ReadCpltCallback(); +} + +/** + * @brief BSP SD Abort callbacks + * @retval None + */ +__weak void BSP_SD_AbortCallback(void) +{ + +} + +/** + * @brief BSP Tx Transfer completed callbacks + * @retval None + */ +__weak void BSP_SD_WriteCpltCallback(void) +{ + +} + +/** + * @brief BSP Rx Transfer completed callbacks + * @retval None + */ +__weak void BSP_SD_ReadCpltCallback(void) +{ + +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sd.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sd.h new file mode 100644 index 00000000..f4487cc7 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sd.h @@ -0,0 +1,164 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_sd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_discovery_sd.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_DISCOVERY_SD_H +#define __STM32F769I_DISCOVERY_SD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY_SD STM32F769I_DISCOVERY SD + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_SD_Exported_Types SD Exported Types + * @{ + */ + +/** + * @brief SD Card information structure + */ +#define BSP_SD_CardInfo HAL_SD_CardInfoTypeDef +/** + * @} + */ + +/** + * @brief SD status structure definition + */ +#define MSD_OK ((uint8_t)0x00) +#define MSD_ERROR ((uint8_t)0x01) +#define MSD_ERROR_SD_NOT_PRESENT ((uint8_t)0x02) + +/** + * @brief SD transfer state definition + */ +#define SD_TRANSFER_OK ((uint8_t)0x00) +#define SD_TRANSFER_BUSY ((uint8_t)0x01) + +/** @defgroup STM32F769I_DISCOVERY_SD_Exported_Constants SD Exported Constants + * @{ + */ +#define SD_PRESENT ((uint8_t)0x01) +#define SD_NOT_PRESENT ((uint8_t)0x00) + +#define SD_DATATIMEOUT ((uint32_t)100000000) + +/* DMA definitions for SD DMA transfer */ +#define __DMAx_TxRx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define SD_DMAx_Tx_CHANNEL DMA_CHANNEL_11 +#define SD_DMAx_Rx_CHANNEL DMA_CHANNEL_11 +#define SD_DMAx_Tx_STREAM DMA2_Stream5 +#define SD_DMAx_Rx_STREAM DMA2_Stream0 +#define SD_DMAx_Tx_IRQn DMA2_Stream5_IRQn +#define SD_DMAx_Rx_IRQn DMA2_Stream0_IRQn +#define BSP_SDMMC_IRQHandler SDMMC2_IRQHandler +#define BSP_SDMMC_DMA_Tx_IRQHandler DMA2_Stream5_IRQHandler +#define BSP_SDMMC_DMA_Rx_IRQHandler DMA2_Stream0_IRQHandler +#define SD_DetectIRQHandler() HAL_GPIO_EXTI_IRQHandler(SD_DETECT_PIN) + + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SD_Exported_Macro STM32F769I Discovery SD Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SD_Exported_Functions STM32F769I Discovery SD Exported Functions + * @{ + */ +uint8_t BSP_SD_Init(void); +uint8_t BSP_SD_DeInit(void); +uint8_t BSP_SD_ITConfig(void); +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks); +uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks); +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); +uint8_t BSP_SD_GetCardState(void); +void BSP_SD_GetCardInfo(HAL_SD_CardInfoTypeDef *CardInfo); +uint8_t BSP_SD_IsDetected(void); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_Detect_MspInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_AbortCallback(void); +void BSP_SD_WriteCpltCallback(void); +void BSP_SD_ReadCpltCallback(void); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_DISCOVERY_SD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sdram.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sdram.c new file mode 100644 index 00000000..1b7f5e5e --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sdram.c @@ -0,0 +1,503 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_sdram.c + * @author MCD Application Team + * @brief This file includes the SDRAM driver for the MT48LC4M32B2B5-6A memory + * device mounted on STM32F769I-DISCOVERY boards. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the MT48LC4M32B2B5-6A SDRAM external memory mounted + on STM32F769I-DISCOVERY board. + - This driver does not need a specific component driver for the SDRAM device + to be included with. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the SDRAM external memory using the BSP_SDRAM_Init() function. This + function includes the MSP layer hardware resources initialization and the + FMC controller configuration to interface with the external SDRAM memory. + o It contains the SDRAM initialization sequence to program the SDRAM external + device using the function BSP_SDRAM_Initialization_sequence(). Note that this + sequence is standard for all SDRAM devices, but can include some differences + from a device to another. If it is the case, the right sequence should be + implemented separately. + + + SDRAM read/write operations + o SDRAM external memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_SDRAM_ReadData()/BSP_SDRAM_WriteData(), or by DMA transfer using the functions + BSP_SDRAM_ReadData_DMA()/BSP_SDRAM_WriteData_DMA(). + o The AHB access is performed with 32-bit width transaction, the DMA transfer + configuration is fixed at single (no burst) word transfer (see the + SDRAM_MspInit() static function). + o User can implement his own functions for read/write access with his desired + configurations. + o If interrupt mode is used for DMA transfer, the function BSP_SDRAM_DMA_IRQHandler() + is called in IRQ handler file, to serve the generated interrupt once the DMA + transfer is complete. + o You can send a command to the SDRAM device in runtime using the function + BSP_SDRAM_Sendcmd(), and giving the desired command as parameter chosen between + the predefined commands of the "FMC_SDRAM_CommandTypeDef" structure. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_sdram.c +- stm32f7xx_ll_fmc.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_discovery_sdram.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_SDRAM STM32F769I_DISCOVERY SDRAM + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_SDRAM_Private_Types_Definitions SDRAM Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SDRAM_Private_Defines SDRAM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SDRAM_Private_Macros SDRAM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SDRAM_Private_Variables SDRAM Private Variables + * @{ + */ +SDRAM_HandleTypeDef sdramHandle; +static FMC_SDRAM_TimingTypeDef Timing; +static FMC_SDRAM_CommandTypeDef Command; +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SDRAM_Private_Function_Prototypes SDRAM Private Function Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SDRAM_Private_Functions SDRAM Private Functions + * @{ + */ + +/** + * @brief Initializes the SDRAM device. + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_Init(void) +{ + static uint8_t sdramstatus = SDRAM_ERROR; + /* SDRAM device configuration */ + sdramHandle.Instance = FMC_SDRAM_DEVICE; + + /* Timing configuration for 100Mhz as SDRAM clock frequency (System clock is up to 200Mhz) */ + Timing.LoadToActiveDelay = 2; + Timing.ExitSelfRefreshDelay = 7; + Timing.SelfRefreshTime = 4; + Timing.RowCycleDelay = 7; + Timing.WriteRecoveryTime = 2; + Timing.RPDelay = 2; + Timing.RCDDelay = 2; + + sdramHandle.Init.SDBank = FMC_SDRAM_BANK1; + sdramHandle.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8; + sdramHandle.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; + sdramHandle.Init.MemoryDataWidth = SDRAM_MEMORY_WIDTH; + sdramHandle.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; + sdramHandle.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3; + sdramHandle.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; + sdramHandle.Init.SDClockPeriod = SDCLOCK_PERIOD; + sdramHandle.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE; + sdramHandle.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; + + /* SDRAM controller initialization */ + + BSP_SDRAM_MspInit(&sdramHandle, NULL); /* __weak function can be rewritten by the application */ + + if(HAL_SDRAM_Init(&sdramHandle, &Timing) != HAL_OK) + { + sdramstatus = SDRAM_ERROR; + } + else + { + sdramstatus = SDRAM_OK; + } + + /* SDRAM initialization sequence */ + BSP_SDRAM_Initialization_sequence(REFRESH_COUNT); + + return sdramstatus; +} + +/** + * @brief DeInitializes the SDRAM device. + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_DeInit(void) +{ + static uint8_t sdramstatus = SDRAM_ERROR; + /* SDRAM device de-initialization */ + sdramHandle.Instance = FMC_SDRAM_DEVICE; + + if(HAL_SDRAM_DeInit(&sdramHandle) != HAL_OK) + { + sdramstatus = SDRAM_ERROR; + } + else + { + sdramstatus = SDRAM_OK; + } + + /* SDRAM controller de-initialization */ + BSP_SDRAM_MspDeInit(&sdramHandle, NULL); + + return sdramstatus; +} + +/** + * @brief Programs the SDRAM device. + * @param RefreshCount: SDRAM refresh counter value + * @retval None + */ +void BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount) +{ + __IO uint32_t tmpmrd = 0; + + /* Step 1: Configure a clock configuration enable command */ + Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 2: Insert 100 us minimum delay */ + /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */ + HAL_Delay(1); + + /* Step 3: Configure a PALL (precharge all) command */ + Command.CommandMode = FMC_SDRAM_CMD_PALL; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 4: Configure an Auto Refresh command */ + Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 8; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 5: Program the external memory mode register */ + tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |\ + SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |\ + SDRAM_MODEREG_CAS_LATENCY_3 |\ + SDRAM_MODEREG_OPERATING_MODE_STANDARD |\ + SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; + + Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = tmpmrd; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 6: Set the refresh rate counter */ + /* Set the device refresh rate */ + HAL_SDRAM_ProgramRefreshRate(&sdramHandle, RefreshCount); +} + +/** + * @brief Reads an amount of data from the SDRAM memory in polling mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_ReadData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Read_32b(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Reads an amount of data from the SDRAM memory in DMA mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_ReadData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Read_DMA(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Writes an amount of data to the SDRAM memory in polling mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_WriteData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Write_32b(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Writes an amount of data to the SDRAM memory in DMA mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_WriteData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Write_DMA(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Sends command to the SDRAM bank. + * @param SdramCmd: Pointer to SDRAM command structure + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_Sendcmd(FMC_SDRAM_CommandTypeDef *SdramCmd) +{ + if(HAL_SDRAM_SendCommand(&sdramHandle, SdramCmd, SDRAM_TIMEOUT) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Initializes SDRAM MSP. + * @param hsdram: SDRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable FMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + + /* Enable chosen DMAx clock */ + __DMAx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF12_FMC; + + /* GPIOD configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8| GPIO_PIN_9 | GPIO_PIN_10 |\ + GPIO_PIN_14 | GPIO_PIN_15; + + + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOE configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7| GPIO_PIN_8 | GPIO_PIN_9 |\ + GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\ + GPIO_PIN_15; + + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOF configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\ + GPIO_PIN_15; + + HAL_GPIO_Init(GPIOF, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4|\ + GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + /* GPIOH configuration */ + gpio_init_structure.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_9 |\ + GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\ + GPIO_PIN_15; + HAL_GPIO_Init(GPIOH, &gpio_init_structure); + + /* GPIOI configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_9 | GPIO_PIN_10; + HAL_GPIO_Init(GPIOI, &gpio_init_structure); + + /* Configure common DMA parameters */ + dma_handle.Init.Channel = SDRAM_DMAx_CHANNEL; + dma_handle.Init.Direction = DMA_MEMORY_TO_MEMORY; + dma_handle.Init.PeriphInc = DMA_PINC_ENABLE; + dma_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_handle.Init.Mode = DMA_NORMAL; + dma_handle.Init.Priority = DMA_PRIORITY_HIGH; + dma_handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + dma_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_handle.Init.MemBurst = DMA_MBURST_SINGLE; + dma_handle.Init.PeriphBurst = DMA_PBURST_SINGLE; + + dma_handle.Instance = SDRAM_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsdram, hdma, dma_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SDRAM_DMAx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SDRAM_DMAx_IRQn); +} + +/** + * @brief DeInitializes SDRAM MSP. + * @param hsdram: SDRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SDRAM_MspDeInit(SDRAM_HandleTypeDef *hsdram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + + /* Disable NVIC configuration for DMA interrupt */ + HAL_NVIC_DisableIRQ(SDRAM_DMAx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_handle.Instance = SDRAM_DMAx_STREAM; + HAL_DMA_DeInit(&dma_handle); + + /* GPIO pins clock, FMC clock and DMA clock can be shut down in the applications + by surcharging this __weak function */ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sdram.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sdram.h new file mode 100644 index 00000000..0b0640e6 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sdram.h @@ -0,0 +1,164 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_sdram.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_discovery_sdram.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_DISCOVERY_SDRAM_H +#define __STM32F769I_DISCOVERY_SDRAM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY_SDRAM + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_SDRAM_Exported_Types SDRAM Exported Types + * @{ + */ + +/** + * @brief SDRAM status structure definition + */ +#define SDRAM_OK ((uint8_t)0x00) +#define SDRAM_ERROR ((uint8_t)0x01) + +/** @defgroup STM32F769I_DISCOVERY_SDRAM_Exported_Constants SDRAM Exported Constants + * @{ + */ + +#define SDRAM_DEVICE_ADDR ((uint32_t)0xC0000000) +#define SDRAM_DEVICE_SIZE ((uint32_t)0x1000000) /* SDRAM device size in MBytes */ + +/* #define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_8 */ +/* #define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_16 */ +#define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_32 + +#define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_2 +/* #define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_3 */ + +#define REFRESH_COUNT ((uint32_t)0x0603) /* SDRAM refresh counter (100Mhz SD clock) */ + +#define SDRAM_TIMEOUT ((uint32_t)0xFFFF) + +/* DMA definitions for SDRAM DMA transfer */ +#define __DMAx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define __DMAx_CLK_DISABLE __HAL_RCC_DMA2_CLK_DISABLE +#define SDRAM_DMAx_CHANNEL DMA_CHANNEL_0 +#define SDRAM_DMAx_STREAM DMA2_Stream0 +#define SDRAM_DMAx_IRQn DMA2_Stream0_IRQn +#define BSP_SDRAM_DMA_IRQHandler DMA2_Stream0_IRQHandler +/** + * @} + */ + +/** + * @brief FMC SDRAM Mode definition register defines + */ +#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) +#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) +#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) +#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) +#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) +#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) +#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SDRAM_Exported_Macro SDRAM Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_SDRAM_Exported_Functions SDRAM Exported Functions + * @{ + */ +uint8_t BSP_SDRAM_Init(void); +uint8_t BSP_SDRAM_DeInit(void); +void BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount); +uint8_t BSP_SDRAM_ReadData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_ReadData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_WriteData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_WriteData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_Sendcmd(FMC_SDRAM_CommandTypeDef *SdramCmd); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram, void *Params); +void BSP_SDRAM_MspDeInit(SDRAM_HandleTypeDef *hsdram, void *Params); + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_DISCOVERY_SDRAM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_ts.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_ts.c new file mode 100644 index 00000000..baf9f0e9 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_ts.c @@ -0,0 +1,484 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_ts.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the Touch + * Screen on STM32F769I-DISCOVERY discovery board. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* File Info : ----------------------------------------------------------------- + User NOTES +1. How To use this driver: +-------------------------- + - This driver is used to drive the touch screen module of the STM32F769I-DISCOVERY + discoveryuation board on the K.O.D Optica Technology 480x800 TFT-LCD mounted on + MB1166 daughter board. The touch screen driver IC inside the K.O.D module KM-040TMP-02 + is a FT6206 by Focal Tech. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the TS module using the BSP_TS_Init() function. This + function includes the MSP layer hardware resources initialization and the + communication layer configuration to start the TS use. The LCD size properties + (x and y) are passed as parameters. + o If TS interrupt mode is desired, you must configure the TS interrupt mode + by calling the function BSP_TS_ITConfig(). The TS interrupt mode is generated + as an external interrupt whenever a touch is detected. + The interrupt mode internally uses the IO functionalities driver driven by + the IO expander, to configure the IT line. + + + Touch screen use + o The touch screen state is captured whenever the function BSP_TS_GetState() is + used. This function returns information about the last LCD touch occurred + in the TS_StateTypeDef structure. + o The IT is handled using the corresponding external interrupt IRQ handler, + the user IT callback treatment is implemented on the same external interrupt + callback. + +------------------------------------------------------------------------------*/ + +/* Dependencies +- stm32f769i_eval_lcd.c +- ft6x06.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_discovery.h" +#include "stm32f769i_discovery_ts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_TS STM32F769I_DISCOVERY TS + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_TS_Private_Types_Definitions TS Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_TS_Private_Defines TS Private Types Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_TS_Private_Macros TS Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_TS_Imported_Variables TS Imported Variables + * @{ + */ + /** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_TS_Private_Variables TS Private Variables + * @{ + */ +static TS_DrvTypeDef *ts_driver; +static uint8_t ts_orientation; +uint8_t I2C_Address = 0; + +/* Table for touchscreen event information display on LCD : table indexed on enum @ref TS_TouchEventTypeDef information */ +char * ts_event_string_tab[TOUCH_EVENT_NB_MAX] = { "None", + "Press down", + "Lift up", + "Contact" + }; + +/* Table for touchscreen gesture Id information display on LCD : table indexed on enum @ref TS_GestureIdTypeDef information */ +char * ts_gesture_id_string_tab[GEST_ID_NB_MAX] = { "None", + "Move Up", + "Move Right", + "Move Down", + "Move Left", + "Zoom In", + "Zoom Out" + }; + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_TS_Private_Function_Prototypes TS Private Function Prototypes + * @{ + */ + +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_TS_Public_Functions TS Public Functions + * @{ + */ + +/** + * @brief Initializes and configures the touch screen functionalities and + * configures all necessary hardware resources (GPIOs, I2C, clocks..). + * @param ts_SizeX : Maximum X size of the TS area on LCD + * @param ts_SizeY : Maximum Y size of the TS area on LCD + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY) +{ + uint8_t ts_status = TS_OK; + uint8_t ts_id1, ts_id2 = 0; + /* Note : I2C_Address is un-initialized here, but is not used at all in init function */ + /* but the prototype of Init() is like that in template and should be respected */ + + /* Initialize the communication channel to sensor (I2C) if necessary */ + /* that is initialization is done only once after a power up */ + ft6x06_ts_drv.Init(I2C_Address); + + ts_id1 = ft6x06_ts_drv.ReadID(TS_I2C_ADDRESS); + if(ts_id1 != FT6206_ID_VALUE) + { + ts_id2 = ft6x06_ts_drv.ReadID(TS_I2C_ADDRESS_A02); + I2C_Address = TS_I2C_ADDRESS_A02; + } + else + { + I2C_Address = TS_I2C_ADDRESS; + } + + /* Scan FT6xx6 TouchScreen IC controller ID register by I2C Read */ + /* Verify this is a FT6206 or FT6336G, otherwise this is an error case */ + if((ts_id1 == FT6206_ID_VALUE) || (ts_id2 == FT6206_ID_VALUE)) + { + /* Found FT6206 : Initialize the TS driver structure */ + ts_driver = &ft6x06_ts_drv; + + /* Get LCD chosen orientation */ + if(ts_SizeX < ts_SizeY) + { + ts_orientation = TS_SWAP_NONE; + } + else + { + ts_orientation = TS_SWAP_XY | TS_SWAP_Y; + } + + if(ts_status == TS_OK) + { + /* Software reset the TouchScreen */ + ts_driver->Reset(I2C_Address); + + /* Calibrate, Configure and Start the TouchScreen driver */ + ts_driver->Start(I2C_Address); + + } /* of if(ts_status == TS_OK) */ + } + else + { + ts_status = TS_DEVICE_NOT_FOUND; + } + + return (ts_status); +} + +/** + * @brief Configures and enables the touch screen interrupts. + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_ITConfig(void) +{ + uint8_t ts_status = TS_OK; + GPIO_InitTypeDef gpio_init_structure; + + /* Msp Init of GPIO used for TS_INT pin coming from TouchScreen driver IC FT6x06 */ + /* When touchscreen is operated in interrupt mode */ + BSP_TS_INT_MspInit(); + + /* Configure Interrupt mode for TS_INT pin falling edge : when a new touch is available */ + /* TS_INT pin is active on low level on new touch available */ + gpio_init_structure.Pin = TS_INT_PIN; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FAST; + gpio_init_structure.Mode = GPIO_MODE_IT_FALLING; + HAL_GPIO_Init(TS_INT_GPIO_PORT, &gpio_init_structure); + + /* Enable and set the TS_INT EXTI Interrupt to an intermediate priority */ + HAL_NVIC_SetPriority((IRQn_Type)(TS_INT_EXTI_IRQn), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(TS_INT_EXTI_IRQn)); + + /* Enable the TS in interrupt mode */ + /* In that case the INT output of FT6206 when new touch is available */ + /* is active on low level and directed on EXTI */ + ts_driver->EnableIT(I2C_Address); + + return (ts_status); +} + +/** + * @brief Returns status and positions of the touch screen. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State) +{ + static uint32_t _x[TS_MAX_NB_TOUCH] = {0, 0}; + static uint32_t _y[TS_MAX_NB_TOUCH] = {0, 0}; + uint8_t ts_status = TS_OK; + uint16_t tmp; + uint16_t Raw_x[TS_MAX_NB_TOUCH]; + uint16_t Raw_y[TS_MAX_NB_TOUCH]; + uint16_t xDiff; + uint16_t yDiff; + uint32_t index; +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + uint32_t weight = 0; + uint32_t area = 0; + uint32_t event = 0; +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + /* Check and update the number of touches active detected */ + TS_State->touchDetected = ts_driver->DetectTouch(I2C_Address); + if(TS_State->touchDetected) + { + for(index=0; index < TS_State->touchDetected; index++) + { + /* Get each touch coordinates */ + ts_driver->GetXY(I2C_Address, &(Raw_x[index]), &(Raw_y[index])); + + if(ts_orientation & TS_SWAP_XY) + { + tmp = Raw_x[index]; + Raw_x[index] = Raw_y[index]; + Raw_y[index] = tmp; + } + + if(ts_orientation & TS_SWAP_X) + { + Raw_x[index] = FT_6206_MAX_WIDTH - 1 - Raw_x[index]; + } + + if(ts_orientation & TS_SWAP_Y) + { + Raw_y[index] = FT_6206_MAX_HEIGHT - 1 - Raw_y[index]; + } + + xDiff = Raw_x[index] > _x[index]? (Raw_x[index] - _x[index]): (_x[index] - Raw_x[index]); + yDiff = Raw_y[index] > _y[index]? (Raw_y[index] - _y[index]): (_y[index] - Raw_y[index]); + + if ((xDiff + yDiff) > 5) + { + _x[index] = Raw_x[index]; + _y[index] = Raw_y[index]; + } + + + TS_State->touchX[index] = _x[index]; + TS_State->touchY[index] = _y[index]; + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + + /* Get touch info related to the current touch */ + ft6x06_TS_GetTouchInfo(I2C_Address, index, &weight, &area, &event); + + /* Update TS_State structure */ + TS_State->touchWeight[index] = weight; + TS_State->touchArea[index] = area; + + /* Remap touch event */ + switch(event) + { + case FT6206_TOUCH_EVT_FLAG_PRESS_DOWN : + TS_State->touchEventId[index] = TOUCH_EVENT_PRESS_DOWN; + break; + case FT6206_TOUCH_EVT_FLAG_LIFT_UP : + TS_State->touchEventId[index] = TOUCH_EVENT_LIFT_UP; + break; + case FT6206_TOUCH_EVT_FLAG_CONTACT : + TS_State->touchEventId[index] = TOUCH_EVENT_CONTACT; + break; + case FT6206_TOUCH_EVT_FLAG_NO_EVENT : + TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT; + break; + default : + ts_status = TS_ERROR; + break; + } /* of switch(event) */ + +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + } /* of for(index=0; index < TS_State->touchDetected; index++) */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + /* Get gesture Id */ + ts_status = BSP_TS_Get_GestureId(TS_State); +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + } /* end of if(TS_State->touchDetected != 0) */ + + return (ts_status); +} + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +/** + * @brief Update gesture Id following a touch detected. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State) +{ + uint32_t gestureId = 0; + uint8_t ts_status = TS_OK; + + /* Get gesture Id */ + ft6x06_TS_GetGestureID(I2C_Address, &gestureId); + + /* Remap gesture Id to a TS_GestureIdTypeDef value */ + switch(gestureId) + { + case FT6206_GEST_ID_NO_GESTURE : + TS_State->gestureId = GEST_ID_NO_GESTURE; + break; + case FT6206_GEST_ID_MOVE_UP : + TS_State->gestureId = GEST_ID_MOVE_UP; + break; + case FT6206_GEST_ID_MOVE_RIGHT : + TS_State->gestureId = GEST_ID_MOVE_RIGHT; + break; + case FT6206_GEST_ID_MOVE_DOWN : + TS_State->gestureId = GEST_ID_MOVE_DOWN; + break; + case FT6206_GEST_ID_MOVE_LEFT : + TS_State->gestureId = GEST_ID_MOVE_LEFT; + break; + case FT6206_GEST_ID_ZOOM_IN : + TS_State->gestureId = GEST_ID_ZOOM_IN; + break; + case FT6206_GEST_ID_ZOOM_OUT : + TS_State->gestureId = GEST_ID_ZOOM_OUT; + break; + default : + ts_status = TS_ERROR; + break; + } /* of switch(gestureId) */ + + return(ts_status); +} +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + +/** @defgroup STM32F769I_DISCOVERY_TS_Private_Functions TS Private Functions + * @{ + */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +/** + * @brief Function used to reset all touch data before a new acquisition + * of touch information. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if OK, TE_ERROR if problem found. + */ +uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State) +{ + uint8_t ts_status = TS_ERROR; + uint32_t index; + + if (TS_State != (TS_StateTypeDef *)NULL) + { + TS_State->gestureId = GEST_ID_NO_GESTURE; + TS_State->touchDetected = 0; + + for(index = 0; index < TS_MAX_NB_TOUCH; index++) + { + TS_State->touchX[index] = 0; + TS_State->touchY[index] = 0; + TS_State->touchArea[index] = 0; + TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT; + TS_State->touchWeight[index] = 0; + } + + ts_status = TS_OK; + + } /* of if (TS_State != (TS_StateTypeDef *)NULL) */ + + return (ts_status); +} +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +/** + * @brief Initializes the TS_INT pin MSP. + * @retval None + */ +__weak void BSP_TS_INT_MspInit(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + TS_INT_GPIO_CLK_ENABLE(); + + /* GPIO configuration in input for TouchScreen interrupt signal on TS_INT pin */ + gpio_init_structure.Pin = TS_INT_PIN; + + gpio_init_structure.Mode = GPIO_MODE_INPUT; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(TS_INT_GPIO_PORT, &gpio_init_structure); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_ts.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_ts.h new file mode 100644 index 00000000..48343099 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_ts.h @@ -0,0 +1,211 @@ +/** + ****************************************************************************** + * @file stm32f769i_discovery_ts.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_discovery_ts.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_DISCOVERY_TS_H +#define __STM32F769I_DISCOVERY_TS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_discovery.h" +#include "stm32f769i_discovery_lcd.h" + +/* Include TouchScreen component driver */ +#include "../Components/ft6x06/ft6x06.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_DISCOVERY + * @{ + */ + +/** @defgroup STM32F769I_DISCOVERY_TS STM32F769I_DISCOVERY TS + * @{ + */ + + /** @defgroup STM32F769I_DISCOVERY_TS_Exported_Constants TS Exported Constants + * @{ + */ +/** @brief With FT6206 : maximum 2 touches detected simultaneously + */ +#define TS_MAX_NB_TOUCH ((uint32_t) FT6206_MAX_DETECTABLE_TOUCH) + +#define TS_NO_IRQ_PENDING ((uint8_t) 0) +#define TS_IRQ_PENDING ((uint8_t) 1) + +#define TS_SWAP_NONE ((uint8_t) 0x01) +#define TS_SWAP_X ((uint8_t) 0x02) +#define TS_SWAP_Y ((uint8_t) 0x04) +#define TS_SWAP_XY ((uint8_t) 0x08) + + /** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_TS_Exported_Types TS Exported Types + * @{ + */ +/** +* @brief TS_StateTypeDef +* Define TS State structure +*/ +typedef struct +{ + uint8_t touchDetected; /*!< Total number of active touches detected at last scan */ + uint16_t touchX[TS_MAX_NB_TOUCH]; /*!< Touch X[0], X[1] coordinates on 12 bits */ + uint16_t touchY[TS_MAX_NB_TOUCH]; /*!< Touch Y[0], Y[1] coordinates on 12 bits */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + uint8_t touchWeight[TS_MAX_NB_TOUCH]; /*!< Touch_Weight[0], Touch_Weight[1] : weight property of touches */ + uint8_t touchEventId[TS_MAX_NB_TOUCH]; /*!< Touch_EventId[0], Touch_EventId[1] : take value of type @ref TS_TouchEventTypeDef */ + uint8_t touchArea[TS_MAX_NB_TOUCH]; /*!< Touch_Area[0], Touch_Area[1] : touch area of each touch */ + uint32_t gestureId; /*!< type of gesture detected : take value of type @ref TS_GestureIdTypeDef */ +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +} TS_StateTypeDef; + +/** + * @brief TS_StatusTypeDef + * Define BSP_TS_xxx() functions possible return value, + * when status is returned by those functions. + */ +typedef enum +{ + TS_OK = 0x00, /*!< Touch Ok */ + TS_ERROR = 0x01, /*!< Touch Error */ + TS_TIMEOUT = 0x02, /*!< Touch Timeout */ + TS_DEVICE_NOT_FOUND = 0x03 /*!< Touchscreen device not found */ +} TS_StatusTypeDef; + +/** + * @brief TS_GestureIdTypeDef + * Define Possible managed gesture identification values returned by touch screen + * driver. + */ +typedef enum +{ + GEST_ID_NO_GESTURE = 0x00, /*!< Gesture not defined / recognized */ + GEST_ID_MOVE_UP = 0x01, /*!< Gesture Move Up */ + GEST_ID_MOVE_RIGHT = 0x02, /*!< Gesture Move Right */ + GEST_ID_MOVE_DOWN = 0x03, /*!< Gesture Move Down */ + GEST_ID_MOVE_LEFT = 0x04, /*!< Gesture Move Left */ + GEST_ID_ZOOM_IN = 0x05, /*!< Gesture Zoom In */ + GEST_ID_ZOOM_OUT = 0x06, /*!< Gesture Zoom Out */ + GEST_ID_NB_MAX = 0x07 /*!< max number of gesture id */ +} TS_GestureIdTypeDef; + +/** + * @brief TS_TouchEventTypeDef + * Define Possible touch events kind as returned values + * by touch screen IC Driver. + */ +typedef enum +{ + TOUCH_EVENT_NO_EVT = 0x00, /*!< Touch Event : undetermined */ + TOUCH_EVENT_PRESS_DOWN = 0x01, /*!< Touch Event Press Down */ + TOUCH_EVENT_LIFT_UP = 0x02, /*!< Touch Event Lift Up */ + TOUCH_EVENT_CONTACT = 0x03, /*!< Touch Event Contact */ + TOUCH_EVENT_NB_MAX = 0x04 /*!< max number of touch events kind */ +} TS_TouchEventTypeDef; + +/** + * @} + */ + +/** @addtogroup STM32F769I_DISCOVERY_TS_Imported_Variables + * @{ + */ +/** + * @brief Table for touchscreen event information display on LCD : + * table indexed on enum @ref TS_TouchEventTypeDef information + */ +extern char * ts_event_string_tab[TOUCH_EVENT_NB_MAX]; + +/** + * @brief Table for touchscreen gesture Id information display on LCD : table indexed + * on enum @ref TS_GestureIdTypeDef information + */ +extern char * ts_gesture_id_string_tab[GEST_ID_NB_MAX]; +/** + * @} + */ + +/** @defgroup STM32F769I_DISCOVERY_TS_Exported_Functions TS Exported Functions + * @{ + */ +uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY); +uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State); + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State); +uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State); +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +uint8_t BSP_TS_ITConfig(void); + +/* These __weak function can be surcharged by application code in case the current settings + need to be changed for specific (example GPIO allocation) */ +void BSP_TS_INT_MspInit(void); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_DISCOVERY_TS_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/Release_Notes.html new file mode 100644 index 00000000..86c852a8 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/Release_Notes.html @@ -0,0 +1,170 @@ + + + + + + + Release Notes for STM32F769I-EVAL BSP Drivers + + + + + +
+
+
+
+
+

Release Notes for STM32F769I-EVAL BSP Drivers

+

Copyright © 2016 STMicroelectronics
+

+ +
+
+
+

License

+This software component is licensed by ST under BSD 3-Clause license, the “Licenseâ€; You may not use this component except in compliance with the License. You may obtain a copy of the License at: +
+https://opensource.org/licenses/BSD-3-Clause +
+

Purpose

+

The BSP (Board Specific Package) drivers are parts of the STM32Cube package based on the HAL drivers and provide a set of high level APIs relative to the hardware components and features in the evaluation boards, discovery kits and nucleo boards coming with the STM32Cube package for a given STM32 serie.

+

The BSP drivers allow a quick access to the boards’ services using high level APIs and without any specific configuration as the link with the HAL and the external components is done in intrinsic within the drivers.

+

From project settings points of view, user has only to add the necessary driver’s files in the workspace and call the needed functions from examples. However some low level configuration functions are weak and can be overridden by the applications if user wants to change some BSP drivers default behavior.

+
+
+

Update History

+
+ +
+

Main Changes

+
    +
  • stm32f769i_eval_camera.c/.h: +
      +
    • Support ov5640 camera sensor
    • +
  • +
  • stm32f769i_eval.c/.h: +
      +
    • Add OV5640 I2C address
    • +
    • Update CAMERA IO Read/Write to support ov5640 camera sensor
    • +
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • stm32f769i_eval_lcd.c: +
      +
    • Fix compilation errors with SW4STM32 toolchain.
    • +
  • +
  • stm32f769i_eval.c: +
      +
    • Upgrade version to v2.0.2
    • +
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • Add general description of BSP drivers
  • +
  • Add Dependencies section
  • +
  • Support of PDSC
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • stm32f769i_eval_sd.c/.h: +
      +
    • Update BSP SD APIs following new HAL SD drivers implementation
    • +
    • Fix BlockSize to 512 bytes
    • +
  • +
  • stm32f769i_eval_ts.c/.h: +
      +
    • Support of FT6336G Touch Screen
    • +
  • +
  • stm32f769i_eval_lcd.c/.h: +
      +
    • Update BSP_LCD_ReadPixel to read correctely ARGB8888 and RGB888 pixels
    • +
  • +
  • stm32f769i_eval_qspi.c/.h: +
      +
    • QSPI write operation improvement
    • +
    • Update CS High Time
    • +
  • +
+

Backward compatibility

+
    +
  • These BSP drivers break the compatibility with previous versions.
  • +
+

Dependencies

+
    +
  • If FatFs is required, “FatFS R0.11 ST modified 20161223†must be used with this version of BSP drivers.
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • stm32f769i_eval_lcd.c/.h: +
      +
    • Support of HDMI video features
    • +
    • Update DSI initialization
    • +
    • Update LTDC clock value
    • +
    • Update LCD_DSI_PIXEL_DATA_FMT_RBG888 and LCD_DSI_PIXEL_DATA_FMT_RBG565 values
    • +
  • +
  • stm32f769i_eval_audio.c/.h: +
      +
    • Support of HDMI audio features
    • +
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • Update typos in drivers comments.
  • +
+
+
+
+ +
+

Main Changes

+
    +
  • First official release of the STM32F769I-EVAL and STM32F779I-EVAL BSP drivers
  • +
+

Dependencies

+
    +
  • STM32F7xx_HAL_Driver V1.2.0
  • +
  • BSP Common V4.0.1
  • +
+
+
+
+
+
+For complete documentation on STM32F769I-EVAL , visit: www.st.com +
+ + diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/_htmresc/mini-st.css b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/_htmresc/mini-st.css new file mode 100644 index 00000000..71fbc14f --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/_htmresc/mini-st.css @@ -0,0 +1,1700 @@ +@charset "UTF-8"; +/* + Flavor name: Default (mini-default) + Author: Angelos Chalaris (chalarangelo@gmail.com) + Maintainers: Angelos Chalaris + mini.css version: v3.0.0-alpha.3 +*/ +/* + Browsers resets and base typography. +*/ +/* Core module CSS variable definitions */ +:root { + --fore-color: #111; + --secondary-fore-color: #444; + --back-color: #f8f8f8; + --secondary-back-color: #f0f0f0; + --blockquote-color: #f57c00; + --pre-color: #1565c0; + --border-color: #aaa; + --secondary-border-color: #ddd; + --heading-ratio: 1.19; + --universal-margin: 0.5rem; + --universal-padding: 0.125rem; + --universal-border-radius: 0.125rem; + --a-link-color: #0277bd; + --a-visited-color: #01579b; } + +html { + font-size: 14px; } + +a, b, del, em, i, ins, q, span, strong, u { + font-size: 1em; } + +html, * { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", Helvetica, sans-serif; + line-height: 1.4; + -webkit-text-size-adjust: 100%; } + +* { + font-size: 1rem; } + +body { + margin: 0; + color: var(--fore-color); + background: var(--back-color); } + +details { + display: block; } + +summary { + display: list-item; } + +abbr[title] { + border-bottom: none; + text-decoration: underline dotted; } + +input { + overflow: visible; } + +img { + max-width: 100%; + height: auto; } + +h1, h2, h3, h4, h5, h6 { + line-height: 1.2; + margin: calc(1.5 * var(--universal-margin)) var(--universal-margin); + font-weight: 500; } + h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { + color: var(--secondary-fore-color); + display: block; + margin-top: -0.25rem; } + +h1 { + font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio) * var(--heading-ratio)); } + +h2 { + font-size: calc(1rem * var(--heading-ratio) * var(--heading-ratio); ); + background: var(--mark-back-color); + font-weight: 600; + padding: 0.1em 0.5em 0.2em 0.5em; + color: var(--mark-fore-color); } + +h3 { + font-size: calc(1rem * var(--heading-ratio)); + padding-left: calc(2 * var(--universal-margin)); + /* background: var(--border-color); */ + } + +h4 { + font-size: 1rem;); + padding-left: calc(4 * var(--universal-margin)); } + +h5 { + font-size: 1rem; } + +h6 { + font-size: calc(1rem / var(--heading-ratio)); } + +p { + margin: var(--universal-margin); } + +ol, ul { + margin: var(--universal-margin); + padding-left: calc(6 * var(--universal-margin)); } + +b, strong { + font-weight: 700; } + +hr { + box-sizing: content-box; + border: 0; + line-height: 1.25em; + margin: var(--universal-margin); + height: 0.0625rem; + background: linear-gradient(to right, transparent, var(--border-color) 20%, var(--border-color) 80%, transparent); } + +blockquote { + display: block; + position: relative; + font-style: italic; + color: var(--secondary-fore-color); + margin: var(--universal-margin); + padding: calc(3 * var(--universal-padding)); + border: 0.0625rem solid var(--secondary-border-color); + border-left: 0.375rem solid var(--blockquote-color); + border-radius: 0 var(--universal-border-radius) var(--universal-border-radius) 0; } + blockquote:before { + position: absolute; + top: calc(0rem - var(--universal-padding)); + left: 0; + font-family: sans-serif; + font-size: 3rem; + font-weight: 700; + content: "\201c"; + color: var(--blockquote-color); } + blockquote[cite]:after { + font-style: normal; + font-size: 0.75em; + font-weight: 700; + content: "\a— " attr(cite); + white-space: pre; } + +code, kbd, pre, samp { + font-family: Menlo, Consolas, monospace; + font-size: 0.85em; } + +code { + background: var(--secondary-back-color); + border-radius: var(--universal-border-radius); + padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); } + +kbd { + background: var(--fore-color); + color: var(--back-color); + border-radius: var(--universal-border-radius); + padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); } + +pre { + overflow: auto; + background: var(--secondary-back-color); + padding: calc(1.5 * var(--universal-padding)); + margin: var(--universal-margin); + border: 0.0625rem solid var(--secondary-border-color); + border-left: 0.25rem solid var(--pre-color); + border-radius: 0 var(--universal-border-radius) var(--universal-border-radius) 0; } + +sup, sub, code, kbd { + line-height: 0; + position: relative; + vertical-align: baseline; } + +small, sup, sub, figcaption { + font-size: 0.75em; } + +sup { + top: -0.5em; } + +sub { + bottom: -0.25em; } + +figure { + margin: var(--universal-margin); } + +figcaption { + color: var(--secondary-fore-color); } + +a { + text-decoration: none; } + a:link { + color: var(--a-link-color); } + a:visited { + color: var(--a-visited-color); } + a:hover, a:focus { + text-decoration: underline; } + +/* + Definitions for the grid system, cards and containers. +*/ +.container { + margin: 0 auto; + padding: 0 calc(1.5 * var(--universal-padding)); } + +.row { + box-sizing: border-box; + display: flex; + flex: 0 1 auto; + flex-flow: row wrap; } + +.col-sm, +[class^='col-sm-'], +[class^='col-sm-offset-'], +.row[class*='cols-sm-'] > * { + box-sizing: border-box; + flex: 0 0 auto; + padding: 0 calc(var(--universal-padding) / 2); } + +.col-sm, +.row.cols-sm > * { + max-width: 100%; + flex-grow: 1; + flex-basis: 0; } + +.col-sm-1, +.row.cols-sm-1 > * { + max-width: 8.3333333333%; + flex-basis: 8.3333333333%; } + +.col-sm-offset-0 { + margin-left: 0; } + +.col-sm-2, +.row.cols-sm-2 > * { + max-width: 16.6666666667%; + flex-basis: 16.6666666667%; } + +.col-sm-offset-1 { + margin-left: 8.3333333333%; } + +.col-sm-3, +.row.cols-sm-3 > * { + max-width: 25%; + flex-basis: 25%; } + +.col-sm-offset-2 { + margin-left: 16.6666666667%; } + +.col-sm-4, +.row.cols-sm-4 > * { + max-width: 33.3333333333%; + flex-basis: 33.3333333333%; } + +.col-sm-offset-3 { + margin-left: 25%; } + +.col-sm-5, +.row.cols-sm-5 > * { + max-width: 41.6666666667%; + flex-basis: 41.6666666667%; } + +.col-sm-offset-4 { + margin-left: 33.3333333333%; } + +.col-sm-6, +.row.cols-sm-6 > * { + max-width: 50%; + flex-basis: 50%; } + +.col-sm-offset-5 { + margin-left: 41.6666666667%; } + +.col-sm-7, +.row.cols-sm-7 > * { + max-width: 58.3333333333%; + flex-basis: 58.3333333333%; } + +.col-sm-offset-6 { + margin-left: 50%; } + +.col-sm-8, +.row.cols-sm-8 > * { + max-width: 66.6666666667%; + flex-basis: 66.6666666667%; } + +.col-sm-offset-7 { + margin-left: 58.3333333333%; } + +.col-sm-9, +.row.cols-sm-9 > * { + max-width: 75%; + flex-basis: 75%; } + +.col-sm-offset-8 { + margin-left: 66.6666666667%; } + +.col-sm-10, +.row.cols-sm-10 > * { + max-width: 83.3333333333%; + flex-basis: 83.3333333333%; } + +.col-sm-offset-9 { + margin-left: 75%; } + +.col-sm-11, +.row.cols-sm-11 > * { + max-width: 91.6666666667%; + flex-basis: 91.6666666667%; } + +.col-sm-offset-10 { + margin-left: 83.3333333333%; } + +.col-sm-12, +.row.cols-sm-12 > * { + max-width: 100%; + flex-basis: 100%; } + +.col-sm-offset-11 { + margin-left: 91.6666666667%; } + +.col-sm-normal { + order: initial; } + +.col-sm-first { + order: -999; } + +.col-sm-last { + order: 999; } + +@media screen and (min-width: 500px) { + .col-md, + [class^='col-md-'], + [class^='col-md-offset-'], + .row[class*='cols-md-'] > * { + box-sizing: border-box; + flex: 0 0 auto; + padding: 0 calc(var(--universal-padding) / 2); } + + .col-md, + .row.cols-md > * { + max-width: 100%; + flex-grow: 1; + flex-basis: 0; } + + .col-md-1, + .row.cols-md-1 > * { + max-width: 8.3333333333%; + flex-basis: 8.3333333333%; } + + .col-md-offset-0 { + margin-left: 0; } + + .col-md-2, + .row.cols-md-2 > * { + max-width: 16.6666666667%; + flex-basis: 16.6666666667%; } + + .col-md-offset-1 { + margin-left: 8.3333333333%; } + + .col-md-3, + .row.cols-md-3 > * { + max-width: 25%; + flex-basis: 25%; } + + .col-md-offset-2 { + margin-left: 16.6666666667%; } + + .col-md-4, + .row.cols-md-4 > * { + max-width: 33.3333333333%; + flex-basis: 33.3333333333%; } + + .col-md-offset-3 { + margin-left: 25%; } + + .col-md-5, + .row.cols-md-5 > * { + max-width: 41.6666666667%; + flex-basis: 41.6666666667%; } + + .col-md-offset-4 { + margin-left: 33.3333333333%; } + + .col-md-6, + .row.cols-md-6 > * { + max-width: 50%; + flex-basis: 50%; } + + .col-md-offset-5 { + margin-left: 41.6666666667%; } + + .col-md-7, + .row.cols-md-7 > * { + max-width: 58.3333333333%; + flex-basis: 58.3333333333%; } + + .col-md-offset-6 { + margin-left: 50%; } + + .col-md-8, + .row.cols-md-8 > * { + max-width: 66.6666666667%; + flex-basis: 66.6666666667%; } + + .col-md-offset-7 { + margin-left: 58.3333333333%; } + + .col-md-9, + .row.cols-md-9 > * { + max-width: 75%; + flex-basis: 75%; } + + .col-md-offset-8 { + margin-left: 66.6666666667%; } + + .col-md-10, + .row.cols-md-10 > * { + max-width: 83.3333333333%; + flex-basis: 83.3333333333%; } + + .col-md-offset-9 { + margin-left: 75%; } + + .col-md-11, + .row.cols-md-11 > * { + max-width: 91.6666666667%; + flex-basis: 91.6666666667%; } + + .col-md-offset-10 { + margin-left: 83.3333333333%; } + + .col-md-12, + .row.cols-md-12 > * { + max-width: 100%; + flex-basis: 100%; } + + .col-md-offset-11 { + margin-left: 91.6666666667%; } + + .col-md-normal { + order: initial; } + + .col-md-first { + order: -999; } + + .col-md-last { + order: 999; } } +@media screen and (min-width: 1280px) { + .col-lg, + [class^='col-lg-'], + [class^='col-lg-offset-'], + .row[class*='cols-lg-'] > * { + box-sizing: border-box; + flex: 0 0 auto; + padding: 0 calc(var(--universal-padding) / 2); } + + .col-lg, + .row.cols-lg > * { + max-width: 100%; + flex-grow: 1; + flex-basis: 0; } + + .col-lg-1, + .row.cols-lg-1 > * { + max-width: 8.3333333333%; + flex-basis: 8.3333333333%; } + + .col-lg-offset-0 { + margin-left: 0; } + + .col-lg-2, + .row.cols-lg-2 > * { + max-width: 16.6666666667%; + flex-basis: 16.6666666667%; } + + .col-lg-offset-1 { + margin-left: 8.3333333333%; } + + .col-lg-3, + .row.cols-lg-3 > * { + max-width: 25%; + flex-basis: 25%; } + + .col-lg-offset-2 { + margin-left: 16.6666666667%; } + + .col-lg-4, + .row.cols-lg-4 > * { + max-width: 33.3333333333%; + flex-basis: 33.3333333333%; } + + .col-lg-offset-3 { + margin-left: 25%; } + + .col-lg-5, + .row.cols-lg-5 > * { + max-width: 41.6666666667%; + flex-basis: 41.6666666667%; } + + .col-lg-offset-4 { + margin-left: 33.3333333333%; } + + .col-lg-6, + .row.cols-lg-6 > * { + max-width: 50%; + flex-basis: 50%; } + + .col-lg-offset-5 { + margin-left: 41.6666666667%; } + + .col-lg-7, + .row.cols-lg-7 > * { + max-width: 58.3333333333%; + flex-basis: 58.3333333333%; } + + .col-lg-offset-6 { + margin-left: 50%; } + + .col-lg-8, + .row.cols-lg-8 > * { + max-width: 66.6666666667%; + flex-basis: 66.6666666667%; } + + .col-lg-offset-7 { + margin-left: 58.3333333333%; } + + .col-lg-9, + .row.cols-lg-9 > * { + max-width: 75%; + flex-basis: 75%; } + + .col-lg-offset-8 { + margin-left: 66.6666666667%; } + + .col-lg-10, + .row.cols-lg-10 > * { + max-width: 83.3333333333%; + flex-basis: 83.3333333333%; } + + .col-lg-offset-9 { + margin-left: 75%; } + + .col-lg-11, + .row.cols-lg-11 > * { + max-width: 91.6666666667%; + flex-basis: 91.6666666667%; } + + .col-lg-offset-10 { + margin-left: 83.3333333333%; } + + .col-lg-12, + .row.cols-lg-12 > * { + max-width: 100%; + flex-basis: 100%; } + + .col-lg-offset-11 { + margin-left: 91.6666666667%; } + + .col-lg-normal { + order: initial; } + + .col-lg-first { + order: -999; } + + .col-lg-last { + order: 999; } } +/* Card component CSS variable definitions */ +:root { + --card-back-color: #f8f8f8; + --card-fore-color: #111; + --card-border-color: #ddd; } + +.card { + display: flex; + flex-direction: column; + justify-content: space-between; + align-self: center; + position: relative; + width: 100%; + background: var(--card-back-color); + color: var(--card-fore-color); + border: 0.0625rem solid var(--card-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); + overflow: hidden; } + @media screen and (min-width: 320px) { + .card { + max-width: 320px; } } + .card > .sectione { + background: var(--card-back-color); + color: var(--card-fore-color); + box-sizing: border-box; + margin: 0; + border: 0; + border-radius: 0; + border-bottom: 0.0625rem solid var(--card-border-color); + padding: var(--universal-padding); + width: 100%; } + .card > .sectione.media { + height: 200px; + padding: 0; + -o-object-fit: cover; + object-fit: cover; } + .card > .sectione:last-child { + border-bottom: 0; } + +/* + Custom elements for card elements. +*/ +@media screen and (min-width: 240px) { + .card.small { + max-width: 240px; } } +@media screen and (min-width: 480px) { + .card.large { + max-width: 480px; } } +.card.fluid { + max-width: 100%; + width: auto; } + +.card.warning { +/* --card-back-color: #ffca28; */ + --card-back-color: #e5b8b7; + --card-border-color: #e8b825; } + +.card.error { + --card-back-color: #b71c1c; + --card-fore-color: #f8f8f8; + --card-border-color: #a71a1a; } + +.card > .sectione.dark { + --card-back-color: #e0e0e0; } + +.card > .sectione.double-padded { + padding: calc(1.5 * var(--universal-padding)); } + +/* + Definitions for forms and input elements. +*/ +/* Input_control module CSS variable definitions */ +:root { + --form-back-color: #f0f0f0; + --form-fore-color: #111; + --form-border-color: #ddd; + --input-back-color: #f8f8f8; + --input-fore-color: #111; + --input-border-color: #ddd; + --input-focus-color: #0288d1; + --input-invalid-color: #d32f2f; + --button-back-color: #e2e2e2; + --button-hover-back-color: #dcdcdc; + --button-fore-color: #212121; + --button-border-color: transparent; + --button-hover-border-color: transparent; + --button-group-border-color: rgba(124, 124, 124, 0.54); } + +form { + background: var(--form-back-color); + color: var(--form-fore-color); + border: 0.0625rem solid var(--form-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); + padding: calc(2 * var(--universal-padding)) var(--universal-padding); } + +fieldset { + border: 0.0625rem solid var(--form-border-color); + border-radius: var(--universal-border-radius); + margin: calc(var(--universal-margin) / 4); + padding: var(--universal-padding); } + +legend { + box-sizing: border-box; + display: table; + max-width: 100%; + white-space: normal; + font-weight: 700; + padding: calc(var(--universal-padding) / 2); } + +label { + padding: calc(var(--universal-padding) / 2) var(--universal-padding); } + +.input-group { + display: inline-block; } + .input-group.fluid { + display: flex; + align-items: center; + justify-content: center; } + .input-group.fluid > input { + max-width: 100%; + flex-grow: 1; + flex-basis: 0px; } + @media screen and (max-width: 499px) { + .input-group.fluid { + align-items: stretch; + flex-direction: column; } } + .input-group.vertical { + display: flex; + align-items: stretch; + flex-direction: column; } + .input-group.vertical > input { + max-width: 100%; + flex-grow: 1; + flex-basis: 0px; } + +[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { + height: auto; } + +[type="search"] { + -webkit-appearance: textfield; + outline-offset: -2px; } + +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; } + +input:not([type]), [type="text"], [type="email"], [type="number"], [type="search"], +[type="password"], [type="url"], [type="tel"], [type="checkbox"], [type="radio"], textarea, select { + box-sizing: border-box; + background: var(--input-back-color); + color: var(--input-fore-color); + border: 0.0625rem solid var(--input-border-color); + border-radius: var(--universal-border-radius); + margin: calc(var(--universal-margin) / 2); + padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); } + +input:not([type="button"]):not([type="submit"]):not([type="reset"]):hover, input:not([type="button"]):not([type="submit"]):not([type="reset"]):focus, textarea:hover, textarea:focus, select:hover, select:focus { + border-color: var(--input-focus-color); + box-shadow: none; } +input:not([type="button"]):not([type="submit"]):not([type="reset"]):invalid, input:not([type="button"]):not([type="submit"]):not([type="reset"]):focus:invalid, textarea:invalid, textarea:focus:invalid, select:invalid, select:focus:invalid { + border-color: var(--input-invalid-color); + box-shadow: none; } +input:not([type="button"]):not([type="submit"]):not([type="reset"])[readonly], textarea[readonly], select[readonly] { + background: var(--secondary-back-color); } + +select { + max-width: 100%; } + +option { + overflow: hidden; + text-overflow: ellipsis; } + +[type="checkbox"], [type="radio"] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + position: relative; + height: calc(1rem + var(--universal-padding) / 2); + width: calc(1rem + var(--universal-padding) / 2); + vertical-align: text-bottom; + padding: 0; + flex-basis: calc(1rem + var(--universal-padding) / 2) !important; + flex-grow: 0 !important; } + [type="checkbox"]:checked:before, [type="radio"]:checked:before { + position: absolute; } + +[type="checkbox"]:checked:before { + content: '\2713'; + font-family: sans-serif; + font-size: calc(1rem + var(--universal-padding) / 2); + top: calc(0rem - var(--universal-padding)); + left: calc(var(--universal-padding) / 4); } + +[type="radio"] { + border-radius: 100%; } + [type="radio"]:checked:before { + border-radius: 100%; + content: ''; + top: calc(0.0625rem + var(--universal-padding) / 2); + left: calc(0.0625rem + var(--universal-padding) / 2); + background: var(--input-fore-color); + width: 0.5rem; + height: 0.5rem; } + +:placeholder-shown { + color: var(--input-fore-color); } + +::-ms-placeholder { + color: var(--input-fore-color); + opacity: 0.54; } + +button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; } + +button, html [type="button"], [type="reset"], [type="submit"] { + -webkit-appearance: button; } + +button { + overflow: visible; + text-transform: none; } + +button, [type="button"], [type="submit"], [type="reset"], +a.button, label.button, .button, +a[role="button"], label[role="button"], [role="button"] { + display: inline-block; + background: var(--button-back-color); + color: var(--button-fore-color); + border: 0.0625rem solid var(--button-border-color); + border-radius: var(--universal-border-radius); + padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); + margin: var(--universal-margin); + text-decoration: none; + cursor: pointer; + transition: background 0.3s; } + button:hover, button:focus, [type="button"]:hover, [type="button"]:focus, [type="submit"]:hover, [type="submit"]:focus, [type="reset"]:hover, [type="reset"]:focus, + a.button:hover, + a.button:focus, label.button:hover, label.button:focus, .button:hover, .button:focus, + a[role="button"]:hover, + a[role="button"]:focus, label[role="button"]:hover, label[role="button"]:focus, [role="button"]:hover, [role="button"]:focus { + background: var(--button-hover-back-color); + border-color: var(--button-hover-border-color); } + +input:disabled, input[disabled], textarea:disabled, textarea[disabled], select:disabled, select[disabled], button:disabled, button[disabled], .button:disabled, .button[disabled], [role="button"]:disabled, [role="button"][disabled] { + cursor: not-allowed; + opacity: 0.75; } + +.button-group { + display: flex; + border: 0.0625rem solid var(--button-group-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); } + .button-group > button, .button-group [type="button"], .button-group > [type="submit"], .button-group > [type="reset"], .button-group > .button, .button-group > [role="button"] { + margin: 0; + max-width: 100%; + flex: 1 1 auto; + text-align: center; + border: 0; + border-radius: 0; + box-shadow: none; } + .button-group > :not(:first-child) { + border-left: 0.0625rem solid var(--button-group-border-color); } + @media screen and (max-width: 499px) { + .button-group { + flex-direction: column; } + .button-group > :not(:first-child) { + border: 0; + border-top: 0.0625rem solid var(--button-group-border-color); } } + +/* + Custom elements for forms and input elements. +*/ +button.primary, [type="button"].primary, [type="submit"].primary, [type="reset"].primary, .button.primary, [role="button"].primary { + --button-back-color: #1976d2; + --button-fore-color: #f8f8f8; } + button.primary:hover, button.primary:focus, [type="button"].primary:hover, [type="button"].primary:focus, [type="submit"].primary:hover, [type="submit"].primary:focus, [type="reset"].primary:hover, [type="reset"].primary:focus, .button.primary:hover, .button.primary:focus, [role="button"].primary:hover, [role="button"].primary:focus { + --button-hover-back-color: #1565c0; } + +button.secondary, [type="button"].secondary, [type="submit"].secondary, [type="reset"].secondary, .button.secondary, [role="button"].secondary { + --button-back-color: #d32f2f; + --button-fore-color: #f8f8f8; } + button.secondary:hover, button.secondary:focus, [type="button"].secondary:hover, [type="button"].secondary:focus, [type="submit"].secondary:hover, [type="submit"].secondary:focus, [type="reset"].secondary:hover, [type="reset"].secondary:focus, .button.secondary:hover, .button.secondary:focus, [role="button"].secondary:hover, [role="button"].secondary:focus { + --button-hover-back-color: #c62828; } + +button.tertiary, [type="button"].tertiary, [type="submit"].tertiary, [type="reset"].tertiary, .button.tertiary, [role="button"].tertiary { + --button-back-color: #308732; + --button-fore-color: #f8f8f8; } + button.tertiary:hover, button.tertiary:focus, [type="button"].tertiary:hover, [type="button"].tertiary:focus, [type="submit"].tertiary:hover, [type="submit"].tertiary:focus, [type="reset"].tertiary:hover, [type="reset"].tertiary:focus, .button.tertiary:hover, .button.tertiary:focus, [role="button"].tertiary:hover, [role="button"].tertiary:focus { + --button-hover-back-color: #277529; } + +button.inverse, [type="button"].inverse, [type="submit"].inverse, [type="reset"].inverse, .button.inverse, [role="button"].inverse { + --button-back-color: #212121; + --button-fore-color: #f8f8f8; } + button.inverse:hover, button.inverse:focus, [type="button"].inverse:hover, [type="button"].inverse:focus, [type="submit"].inverse:hover, [type="submit"].inverse:focus, [type="reset"].inverse:hover, [type="reset"].inverse:focus, .button.inverse:hover, .button.inverse:focus, [role="button"].inverse:hover, [role="button"].inverse:focus { + --button-hover-back-color: #111; } + +button.small, [type="button"].small, [type="submit"].small, [type="reset"].small, .button.small, [role="button"].small { + padding: calc(0.5 * var(--universal-padding)) calc(0.75 * var(--universal-padding)); + margin: var(--universal-margin); } + +button.large, [type="button"].large, [type="submit"].large, [type="reset"].large, .button.large, [role="button"].large { + padding: calc(1.5 * var(--universal-padding)) calc(2 * var(--universal-padding)); + margin: var(--universal-margin); } + +/* + Definitions for navigation elements. +*/ +/* Navigation module CSS variable definitions */ +:root { + --header-back-color: #f8f8f8; + --header-hover-back-color: #f0f0f0; + --header-fore-color: #444; + --header-border-color: #ddd; + --nav-back-color: #f8f8f8; + --nav-hover-back-color: #f0f0f0; + --nav-fore-color: #444; + --nav-border-color: #ddd; + --nav-link-color: #0277bd; + --footer-fore-color: #444; + --footer-back-color: #f8f8f8; + --footer-border-color: #ddd; + --footer-link-color: #0277bd; + --drawer-back-color: #f8f8f8; + --drawer-hover-back-color: #f0f0f0; + --drawer-border-color: #ddd; + --drawer-close-color: #444; } + +header { + height: 3.1875rem; + background: var(--header-back-color); + color: var(--header-fore-color); + border-bottom: 0.0625rem solid var(--header-border-color); + padding: calc(var(--universal-padding) / 4) 0; + white-space: nowrap; + overflow-x: auto; + overflow-y: hidden; } + header.row { + box-sizing: content-box; } + header .logo { + color: var(--header-fore-color); + font-size: 1.75rem; + padding: var(--universal-padding) calc(2 * var(--universal-padding)); + text-decoration: none; } + header button, header [type="button"], header .button, header [role="button"] { + box-sizing: border-box; + position: relative; + top: calc(0rem - var(--universal-padding) / 4); + height: calc(3.1875rem + var(--universal-padding) / 2); + background: var(--header-back-color); + line-height: calc(3.1875rem - var(--universal-padding) * 1.5); + text-align: center; + color: var(--header-fore-color); + border: 0; + border-radius: 0; + margin: 0; + text-transform: uppercase; } + header button:hover, header button:focus, header [type="button"]:hover, header [type="button"]:focus, header .button:hover, header .button:focus, header [role="button"]:hover, header [role="button"]:focus { + background: var(--header-hover-back-color); } + +nav { + background: var(--nav-back-color); + color: var(--nav-fore-color); + border: 0.0625rem solid var(--nav-border-color); + border-radius: var(--universal-border-radius); + margin: var(--universal-margin); } + nav * { + padding: var(--universal-padding) calc(1.5 * var(--universal-padding)); } + nav a, nav a:visited { + display: block; + color: var(--nav-link-color); + border-radius: var(--universal-border-radius); + transition: background 0.3s; } + nav a:hover, nav a:focus, nav a:visited:hover, nav a:visited:focus { + text-decoration: none; + background: var(--nav-hover-back-color); } + nav .sublink-1 { + position: relative; + margin-left: calc(2 * var(--universal-padding)); } + nav .sublink-1:before { + position: absolute; + left: calc(var(--universal-padding) - 1 * var(--universal-padding)); + top: -0.0625rem; + content: ''; + height: 100%; + border: 0.0625rem solid var(--nav-border-color); + border-left: 0; } + nav .sublink-2 { + position: relative; + margin-left: calc(4 * var(--universal-padding)); } + nav .sublink-2:before { + position: absolute; + left: calc(var(--universal-padding) - 3 * var(--universal-padding)); + top: -0.0625rem; + content: ''; + height: 100%; + border: 0.0625rem solid var(--nav-border-color); + border-left: 0; } + +footer { + background: var(--footer-back-color); + color: var(--footer-fore-color); + border-top: 0.0625rem solid var(--footer-border-color); + padding: calc(2 * var(--universal-padding)) var(--universal-padding); + font-size: 0.875rem; } + footer a, footer a:visited { + color: var(--footer-link-color); } + +header.sticky { + position: -webkit-sticky; + position: sticky; + z-index: 1101; + top: 0; } + +footer.sticky { + position: -webkit-sticky; + position: sticky; + z-index: 1101; + bottom: 0; } + +.drawer-toggle:before { + display: inline-block; + position: relative; + vertical-align: bottom; + content: '\00a0\2261\00a0'; + font-family: sans-serif; + font-size: 1.5em; } +@media screen and (min-width: 500px) { + .drawer-toggle:not(.persistent) { + display: none; } } + +[type="checkbox"].drawer { + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); } + [type="checkbox"].drawer + * { + display: block; + box-sizing: border-box; + position: fixed; + top: 0; + width: 320px; + height: 100vh; + overflow-y: auto; + background: var(--drawer-back-color); + border: 0.0625rem solid var(--drawer-border-color); + border-radius: 0; + margin: 0; + z-index: 1110; + right: -320px; + transition: right 0.3s; } + [type="checkbox"].drawer + * .drawer-close { + position: absolute; + top: var(--universal-margin); + right: var(--universal-margin); + z-index: 1111; + width: 2rem; + height: 2rem; + border-radius: var(--universal-border-radius); + padding: var(--universal-padding); + margin: 0; + cursor: pointer; + transition: background 0.3s; } + [type="checkbox"].drawer + * .drawer-close:before { + display: block; + content: '\00D7'; + color: var(--drawer-close-color); + position: relative; + font-family: sans-serif; + font-size: 2rem; + line-height: 1; + text-align: center; } + [type="checkbox"].drawer + * .drawer-close:hover, [type="checkbox"].drawer + * .drawer-close:focus { + background: var(--drawer-hover-back-color); } + @media screen and (max-width: 320px) { + [type="checkbox"].drawer + * { + width: 100%; } } + [type="checkbox"].drawer:checked + * { + right: 0; } + @media screen and (min-width: 500px) { + [type="checkbox"].drawer:not(.persistent) + * { + position: static; + height: 100%; + z-index: 1100; } + [type="checkbox"].drawer:not(.persistent) + * .drawer-close { + display: none; } } + +/* + Definitions for the responsive table component. +*/ +/* Table module CSS variable definitions. */ +:root { + --table-border-color: #aaa; + --table-border-separator-color: #666; + --table-head-back-color: #e6e6e6; + --table-head-fore-color: #111; + --table-body-back-color: #f8f8f8; + --table-body-fore-color: #111; + --table-body-alt-back-color: #eee; } + +table { + border-collapse: separate; + border-spacing: 0; + : margin: calc(1.5 * var(--universal-margin)) var(--universal-margin); + display: flex; + flex: 0 1 auto; + flex-flow: row wrap; + padding: var(--universal-padding); + padding-top: 0; + margin: calc(1.5 * var(--universal-margin)) var(--universal-margin); } + table caption { + font-size: 1.25 * rem; + margin: calc(2 * var(--universal-margin)) 0; + max-width: 100%; + flex: 0 0 100%; + text-align: left;} + table thead, table tbody { + display: flex; + flex-flow: row wrap; + border: 0.0625rem solid var(--table-border-color); } + table thead { + z-index: 999; + border-radius: var(--universal-border-radius) var(--universal-border-radius) 0 0; + border-bottom: 0.0625rem solid var(--table-border-separator-color); } + table tbody { + border-top: 0; + margin-top: calc(0 - var(--universal-margin)); + border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); } + table tr { + display: flex; + padding: 0; } + table th, table td { + padding: calc(0.5 * var(--universal-padding)); + font-size: 0.9rem; } + table th { + text-align: left; + background: var(--table-head-back-color); + color: var(--table-head-fore-color); } + table td { + background: var(--table-body-back-color); + color: var(--table-body-fore-color); + border-top: 0.0625rem solid var(--table-border-color); } + +table:not(.horizontal) { + overflow: auto; + max-height: 850px; } + table:not(.horizontal) thead, table:not(.horizontal) tbody { + max-width: 100%; + flex: 0 0 100%; } + table:not(.horizontal) tr { + flex-flow: row wrap; + flex: 0 0 100%; } + table:not(.horizontal) th, table:not(.horizontal) td { + flex: 1 0 0%; + overflow: hidden; + text-overflow: ellipsis; } + table:not(.horizontal) thead { + position: sticky; + top: 0; } + table:not(.horizontal) tbody tr:first-child td { + border-top: 0; } + +table.horizontal { + border: 0; } + table.horizontal thead, table.horizontal tbody { + border: 0; + flex-flow: row nowrap; } + table.horizontal tbody { + overflow: auto; + justify-content: space-between; + flex: 1 0 0; + margin-left: calc( 4 * var(--universal-margin)); + padding-bottom: calc(var(--universal-padding) / 4); } + table.horizontal tr { + flex-direction: column; + flex: 1 0 auto; } + table.horizontal th, table.horizontal td { + width: 100%; + border: 0; + border-bottom: 0.0625rem solid var(--table-border-color); } + table.horizontal th:not(:first-child), table.horizontal td:not(:first-child) { + border-top: 0; } + table.horizontal th { + text-align: right; + border-left: 0.0625rem solid var(--table-border-color); + border-right: 0.0625rem solid var(--table-border-separator-color); } + table.horizontal thead tr:first-child { + padding-left: 0; } + table.horizontal th:first-child, table.horizontal td:first-child { + border-top: 0.0625rem solid var(--table-border-color); } + table.horizontal tbody tr:last-child td { + border-right: 0.0625rem solid var(--table-border-color); } + table.horizontal tbody tr:last-child td:first-child { + border-top-right-radius: 0.25rem; } + table.horizontal tbody tr:last-child td:last-child { + border-bottom-right-radius: 0.25rem; } + table.horizontal thead tr:first-child th:first-child { + border-top-left-radius: 0.25rem; } + table.horizontal thead tr:first-child th:last-child { + border-bottom-left-radius: 0.25rem; } + +@media screen and (max-width: 499px) { + table, table.horizontal { + border-collapse: collapse; + border: 0; + width: 100%; + display: table; } + table thead, table th, table.horizontal thead, table.horizontal th { + border: 0; + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); } + table tbody, table.horizontal tbody { + border: 0; + display: table-row-group; } + table tr, table.horizontal tr { + display: block; + border: 0.0625rem solid var(--table-border-color); + border-radius: var(--universal-border-radius); + background: #fafafa; + padding: var(--universal-padding); + margin: var(--universal-margin); + margin-bottom: calc(2 * var(--universal-margin)); } + table th, table td, table.horizontal th, table.horizontal td { + width: auto; } + table td, table.horizontal td { + display: block; + border: 0; + text-align: right; } + table td:before, table.horizontal td:before { + content: attr(data-label); + float: left; + font-weight: 600; } + table th:first-child, table td:first-child, table.horizontal th:first-child, table.horizontal td:first-child { + border-top: 0; } + table tbody tr:last-child td, table.horizontal tbody tr:last-child td { + border-right: 0; } } +:root { + --table-body-alt-back-color: #eee; } + +table tr:nth-of-type(2n) > td { + background: var(--table-body-alt-back-color); } + +@media screen and (max-width: 500px) { + table tr:nth-of-type(2n) { + background: var(--table-body-alt-back-color); } } +:root { + --table-body-hover-back-color: #90caf9; } + +table.hoverable tr:hover, table.hoverable tr:hover > td, table.hoverable tr:focus, table.hoverable tr:focus > td { + background: var(--table-body-hover-back-color); } + +@media screen and (max-width: 500px) { + table.hoverable tr:hover, table.hoverable tr:hover > td, table.hoverable tr:focus, table.hoverable tr:focus > td { + background: var(--table-body-hover-back-color); } } +/* + Definitions for contextual background elements, toasts and tooltips. +*/ +/* Contextual module CSS variable definitions */ +:root { + --mark-back-color: #0277bd; + --mark-fore-color: #fafafa; } + +mark { + background: var(--mark-back-color); + color: var(--mark-fore-color); + font-size: 0.95em; + line-height: 1em; + border-radius: var(--universal-border-radius); + padding: calc(var(--universal-padding) / 4) calc(var(--universal-padding) / 2); } + mark.inline-block { + display: inline-block; + font-size: 1em; + line-height: 1.5; + padding: calc(var(--universal-padding) / 2) var(--universal-padding); } + +:root { + --toast-back-color: #424242; + --toast-fore-color: #fafafa; } + +.toast { + position: fixed; + bottom: calc(var(--universal-margin) * 3); + left: 50%; + transform: translate(-50%, -50%); + z-index: 1111; + color: var(--toast-fore-color); + background: var(--toast-back-color); + border-radius: calc(var(--universal-border-radius) * 16); + padding: var(--universal-padding) calc(var(--universal-padding) * 3); } + +:root { + --tooltip-back-color: #212121; + --tooltip-fore-color: #fafafa; } + +.tooltip { + position: relative; + display: inline-block; } + .tooltip:before, .tooltip:after { + position: absolute; + opacity: 0; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + transition: all 0.3s; + z-index: 1010; + left: 50%; } + .tooltip:not(.bottom):before, .tooltip:not(.bottom):after { + bottom: 75%; } + .tooltip.bottom:before, .tooltip.bottom:after { + top: 75%; } + .tooltip:hover:before, .tooltip:hover:after, .tooltip:focus:before, .tooltip:focus:after { + opacity: 1; + clip: auto; + -webkit-clip-path: inset(0%); + clip-path: inset(0%); } + .tooltip:before { + content: ''; + background: transparent; + border: var(--universal-margin) solid transparent; + left: calc(50% - var(--universal-margin)); } + .tooltip:not(.bottom):before { + border-top-color: #212121; } + .tooltip.bottom:before { + border-bottom-color: #212121; } + .tooltip:after { + content: attr(aria-label); + color: var(--tooltip-fore-color); + background: var(--tooltip-back-color); + border-radius: var(--universal-border-radius); + padding: var(--universal-padding); + white-space: nowrap; + transform: translateX(-50%); } + .tooltip:not(.bottom):after { + margin-bottom: calc(2 * var(--universal-margin)); } + .tooltip.bottom:after { + margin-top: calc(2 * var(--universal-margin)); } + +:root { + --modal-overlay-color: rgba(0, 0, 0, 0.45); + --modal-close-color: #444; + --modal-close-hover-color: #f0f0f0; } + +[type="checkbox"].modal { + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); } + [type="checkbox"].modal + div { + position: fixed; + top: 0; + left: 0; + display: none; + width: 100vw; + height: 100vh; + background: var(--modal-overlay-color); } + [type="checkbox"].modal + div .card { + margin: 0 auto; + max-height: 50vh; + overflow: auto; } + [type="checkbox"].modal + div .card .modal-close { + position: absolute; + top: 0; + right: 0; + width: 1.75rem; + height: 1.75rem; + border-radius: var(--universal-border-radius); + padding: var(--universal-padding); + margin: 0; + cursor: pointer; + transition: background 0.3s; } + [type="checkbox"].modal + div .card .modal-close:before { + display: block; + content: '\00D7'; + color: var(--modal-close-color); + position: relative; + font-family: sans-serif; + font-size: 1.75rem; + line-height: 1; + text-align: center; } + [type="checkbox"].modal + div .card .modal-close:hover, [type="checkbox"].modal + div .card .modal-close:focus { + background: var(--modal-close-hover-color); } + [type="checkbox"].modal:checked + div { + display: flex; + flex: 0 1 auto; + z-index: 1200; } + [type="checkbox"].modal:checked + div .card .modal-close { + z-index: 1211; } + +:root { + --collapse-label-back-color: #e8e8e8; + --collapse-label-fore-color: #212121; + --collapse-label-hover-back-color: #f0f0f0; + --collapse-selected-label-back-color: #ececec; + --collapse-border-color: #ddd; + --collapse-content-back-color: #fafafa; + --collapse-selected-label-border-color: #0277bd; } + +.collapse { + width: calc(100% - 2 * var(--universal-margin)); + opacity: 1; + display: flex; + flex-direction: column; + margin: var(--universal-margin); + border-radius: var(--universal-border-radius); } + .collapse > [type="radio"], .collapse > [type="checkbox"] { + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); } + .collapse > label { + flex-grow: 1; + display: inline-block; + height: 1.5rem; + cursor: pointer; + transition: background 0.3s; + color: var(--collapse-label-fore-color); + background: var(--collapse-label-back-color); + border: 0.0625rem solid var(--collapse-border-color); + padding: calc(1.5 * var(--universal-padding)); } + .collapse > label:hover, .collapse > label:focus { + background: var(--collapse-label-hover-back-color); } + .collapse > label + div { + flex-basis: auto; + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + position: absolute; + clip: rect(0 0 0 0); + -webkit-clip-path: inset(100%); + clip-path: inset(100%); + transition: max-height 0.3s; + max-height: 1px; } + .collapse > :checked + label { + background: var(--collapse-selected-label-back-color); + border-bottom-color: var(--collapse-selected-label-border-color); } + .collapse > :checked + label + div { + box-sizing: border-box; + position: relative; + width: 100%; + height: auto; + overflow: auto; + margin: 0; + background: var(--collapse-content-back-color); + border: 0.0625rem solid var(--collapse-border-color); + border-top: 0; + padding: var(--universal-padding); + clip: auto; + -webkit-clip-path: inset(0%); + clip-path: inset(0%); + max-height: 850px; } + .collapse > label:not(:first-of-type) { + border-top: 0; } + .collapse > label:first-of-type { + border-radius: var(--universal-border-radius) var(--universal-border-radius) 0 0; } + .collapse > label:last-of-type:not(:first-of-type) { + border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); } + .collapse > label:last-of-type:first-of-type { + border-radius: var(--universal-border-radius); } + .collapse > :checked:last-of-type:not(:first-of-type) + label { + border-radius: 0; } + .collapse > :checked:last-of-type + label + div { + border-radius: 0 0 var(--universal-border-radius) var(--universal-border-radius); } + +/* + Custom elements for contextual background elements, toasts and tooltips. +*/ +mark.secondary { + --mark-back-color: #d32f2f; } + +mark.tertiary { + --mark-back-color: #308732; } + +mark.tag { + padding: calc(var(--universal-padding)/2) var(--universal-padding); + border-radius: 1em; } + +/* + Definitions for progress elements and spinners. +*/ +/* Progess module CSS variable definitions */ +:root { + --progress-back-color: #ddd; + --progress-fore-color: #555; } + +progress { + display: block; + vertical-align: baseline; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + height: 0.75rem; + width: calc(100% - 2 * var(--universal-margin)); + margin: var(--universal-margin); + border: 0; + border-radius: calc(2 * var(--universal-border-radius)); + background: var(--progress-back-color); + color: var(--progress-fore-color); } + progress::-webkit-progress-value { + background: var(--progress-fore-color); + border-top-left-radius: calc(2 * var(--universal-border-radius)); + border-bottom-left-radius: calc(2 * var(--universal-border-radius)); } + progress::-webkit-progress-bar { + background: var(--progress-back-color); } + progress::-moz-progress-bar { + background: var(--progress-fore-color); + border-top-left-radius: calc(2 * var(--universal-border-radius)); + border-bottom-left-radius: calc(2 * var(--universal-border-radius)); } + progress[value="1000"]::-webkit-progress-value { + border-radius: calc(2 * var(--universal-border-radius)); } + progress[value="1000"]::-moz-progress-bar { + border-radius: calc(2 * var(--universal-border-radius)); } + progress.inline { + display: inline-block; + vertical-align: middle; + width: 60%; } + +:root { + --spinner-back-color: #ddd; + --spinner-fore-color: #555; } + +@keyframes spinner-donut-anim { + 0% { + transform: rotate(0deg); } + 100% { + transform: rotate(360deg); } } +.spinner { + display: inline-block; + margin: var(--universal-margin); + border: 0.25rem solid var(--spinner-back-color); + border-left: 0.25rem solid var(--spinner-fore-color); + border-radius: 50%; + width: 1.25rem; + height: 1.25rem; + animation: spinner-donut-anim 1.2s linear infinite; } + +/* + Custom elements for progress bars and spinners. +*/ +progress.primary { + --progress-fore-color: #1976d2; } + +progress.secondary { + --progress-fore-color: #d32f2f; } + +progress.tertiary { + --progress-fore-color: #308732; } + +.spinner.primary { + --spinner-fore-color: #1976d2; } + +.spinner.secondary { + --spinner-fore-color: #d32f2f; } + +.spinner.tertiary { + --spinner-fore-color: #308732; } + +/* + Definitions for icons - powered by Feather (https://feathericons.com/). +*/ +span[class^='icon-'] { + display: inline-block; + height: 1em; + width: 1em; + vertical-align: -0.125em; + background-size: contain; + margin: 0 calc(var(--universal-margin) / 4); } + span[class^='icon-'].secondary { + -webkit-filter: invert(25%); + filter: invert(25%); } + span[class^='icon-'].inverse { + -webkit-filter: invert(100%); + filter: invert(100%); } + +span.icon-alert { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12' y2='16'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-bookmark { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-calendar { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-credit { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='1' y='4' width='22' height='16' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='1' y1='10' x2='23' y2='10'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-edit { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 14.66V20a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5.34'%3E%3C/path%3E%3Cpolygon points='18 2 22 6 12 16 8 16 8 12 18 2'%3E%3C/polygon%3E%3C/svg%3E"); } +span.icon-link { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'%3E%3C/path%3E%3Cpolyline points='15 3 21 3 21 9'%3E%3C/polyline%3E%3Cline x1='10' y1='14' x2='21' y2='3'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-help { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3'%3E%3C/path%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='17' x2='12' y2='17'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-home { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z'%3E%3C/path%3E%3Cpolyline points='9 22 9 12 15 12 15 22'%3E%3C/polyline%3E%3C/svg%3E"); } +span.icon-info { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='16' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='8' x2='12' y2='8'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-lock { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='11' width='18' height='11' rx='2' ry='2'%3E%3C/rect%3E%3Cpath d='M7 11V7a5 5 0 0 1 10 0v4'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-mail { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z'%3E%3C/path%3E%3Cpolyline points='22,6 12,13 2,6'%3E%3C/polyline%3E%3C/svg%3E"); } +span.icon-location { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z'%3E%3C/path%3E%3Ccircle cx='12' cy='10' r='3'%3E%3C/circle%3E%3C/svg%3E"); } +span.icon-phone { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-rss { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 11a9 9 0 0 1 9 9'%3E%3C/path%3E%3Cpath d='M4 4a16 16 0 0 1 16 16'%3E%3C/path%3E%3Ccircle cx='5' cy='19' r='1'%3E%3C/circle%3E%3C/svg%3E"); } +span.icon-search { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-settings { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='3'%3E%3C/circle%3E%3Cpath d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-share { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='18' cy='5' r='3'%3E%3C/circle%3E%3Ccircle cx='6' cy='12' r='3'%3E%3C/circle%3E%3Ccircle cx='18' cy='19' r='3'%3E%3C/circle%3E%3Cline x1='8.59' y1='13.51' x2='15.42' y2='17.49'%3E%3C/line%3E%3Cline x1='15.41' y1='6.51' x2='8.59' y2='10.49'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-cart { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='21' r='1'%3E%3C/circle%3E%3Ccircle cx='20' cy='21' r='1'%3E%3C/circle%3E%3Cpath d='M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6'%3E%3C/path%3E%3C/svg%3E"); } +span.icon-upload { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'%3E%3C/path%3E%3Cpolyline points='17 8 12 3 7 8'%3E%3C/polyline%3E%3Cline x1='12' y1='3' x2='12' y2='15'%3E%3C/line%3E%3C/svg%3E"); } +span.icon-user { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='12' cy='7' r='4'%3E%3C/circle%3E%3C/svg%3E"); } + +/* + Definitions for utilities and helper classes. +*/ +/* Utility module CSS variable definitions */ +:root { + --generic-border-color: rgba(0, 0, 0, 0.3); + --generic-box-shadow: 0 0.25rem 0.25rem 0 rgba(0, 0, 0, 0.125), 0 0.125rem 0.125rem -0.125rem rgba(0, 0, 0, 0.25); } + +.hidden { + display: none !important; } + +.visually-hidden { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; } + +.bordered { + border: 0.0625rem solid var(--generic-border-color) !important; } + +.rounded { + border-radius: var(--universal-border-radius) !important; } + +.circular { + border-radius: 50% !important; } + +.shadowed { + box-shadow: var(--generic-box-shadow) !important; } + +.responsive-margin { + margin: calc(var(--universal-margin) / 4) !important; } + @media screen and (min-width: 500px) { + .responsive-margin { + margin: calc(var(--universal-margin) / 2) !important; } } + @media screen and (min-width: 1280px) { + .responsive-margin { + margin: var(--universal-margin) !important; } } + +.responsive-padding { + padding: calc(var(--universal-padding) / 4) !important; } + @media screen and (min-width: 500px) { + .responsive-padding { + padding: calc(var(--universal-padding) / 2) !important; } } + @media screen and (min-width: 1280px) { + .responsive-padding { + padding: var(--universal-padding) !important; } } + +@media screen and (max-width: 499px) { + .hidden-sm { + display: none !important; } } +@media screen and (min-width: 500px) and (max-width: 1279px) { + .hidden-md { + display: none !important; } } +@media screen and (min-width: 1280px) { + .hidden-lg { + display: none !important; } } +@media screen and (max-width: 499px) { + .visually-hidden-sm { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; } } +@media screen and (min-width: 500px) and (max-width: 1279px) { + .visually-hidden-md { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; } } +@media screen and (min-width: 1280px) { + .visually-hidden-lg { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + border: 0 !important; + padding: 0 !important; + clip: rect(0 0 0 0) !important; + -webkit-clip-path: inset(100%) !important; + clip-path: inset(100%) !important; + overflow: hidden !important; } } + +/*# sourceMappingURL=mini-default.css.map */ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/_htmresc/st_logo.png b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/_htmresc/st_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8b80057fd3a454a97de1c9d732b7fede82c83227 GIT binary patch literal 18616 zcmbTd^-~<*6D~X~?jgaQV8LAj0X_tm1Ydk1xVy{Z3GPmS;IP2r4oh%%cMl#Qcz~Pl zz5l>lZ`GVRHB&V|boY7A^z(F|Z=Y4=aIwg-006*MkpHOuZ?5<^0x;12-SsK9!v0Mt zmQpHG08kT${nrHb-!rC@ysj$%ki7ceKq56ESOEZeJ%x`_nqEey{^(v>eK${gL>pJ% zX8+KBAR_W-jhDrs{egi|sP<73DP`UFoa(>xj;8qknEx2bL~2@t%3k>}hnl@CWQrW@ zqfK>@e3$sL-m%ftg0YAkk!@=P!Ognuz(zhb|Tux{FeX<<7(5oLVU8=W*sUZ*$TqlSb6o1O0a zzeP#ZW!;?#>0N5v?0D|q?mzD8-<^@1V0FH{fY}2A9ooXbylcB6Y>PVo4nMxLi|AWA z8M(b#9`j|%0v7ktATOSzsh-T7%Wqa>t*x!29M*iDetE6#^`?iEoQW5F*w7rjcWYw>-UyKyDHetK@Im)qdu0o-zudq@gQN3)r z=(%XIh|%7(Y}2mODA6--)=u;7mi|lUCki50L@QOyZN@2N`Bwwn9et)BF?yQr9`Sn# ze!a;09%cuNiCJ+Hwx|5Sw&L`0rJvq<$7D5j#Y=O^YcW)1x!+MVRWRVHrXDj~g@40Q zBvp_niE6-dasJKX&t@%;X`7_R9QhT$w_Dv~zW73kCM;9WC z#^@^R#^^HZ#`rQ5ZjC*^uYUMgw=ae5*IV2JyEL@LlJ1k!yA8p=fmyQ={`Pjq&sK}Y>k9r>*Y-3njDRLc8z*D?su--n+y(fpV8FB zwS%vLw=L>F9>rMJzXaXgg5NRvaHPKO=qdV`%ecKE^q=CNs6^=Vl)5QG9h0>AKM-1F zvU-S)!Vnz~yg}XNmnaKSqm&}<1}#nOBCWZsLvn3_pkm8Z)~*KF8yv=yRk*!4rf$7T zT*ey^g`%>`O82HoVNPMCaM^5e_Eeop`^`Wsro=Q9SzJ-{LW5j1QdRH>Oq5bEX({TJ-TNGPvNBrk5{my=8FEQ%0fftv4 z)$FK)-usf%cyd|Y@=r@u!~HI3-5_Q=E%R!AkEqtv$Yv%Zit4K`i*n5tM!wdwLFM?% z@N0D&tLS9%TD>`41R~`%HzXtZS6pjo$}fsAA6cq`&Llq^TE@#ID4eU}(xZH$-0oa>g$RMe)N_S(=w@nXEL&?{|e zd%-=H@Ei^9kz3up?3!?QYr2O7^M9)q_E2E@^vESGQ&5WzDh<(QgQEd3BICrRm8O)S!fPO#z(h0}Vk) zolMw(Ecl!UD7xMUH0>?+9qzTMCMQxcM+Od*!L7F!tiwSSG>D@|J~*c~gu?`RewztA z1cO8*h9GGR{``zPp9t6vZJ81Ar<-bz38Jv-ro`wI#Mq&-k$*5tL<>Pk=)T1H_z8YhPJDWCuq5c#f&iDRo3$~XHhc-#T3{whJvB?;N^IKpX^H#=oYNa@u&^9He20t za7qlYKRH^S(Tj2{XC=lPI|MVMOVVX4V8cbx(9Ix%YK__iyN9E(k)118*aO-OzZNT# zbhE^f=Cze>bdhX>8xBFW70+=Tb@QnIyKKmQGt`}ZHXrVVWgxIT1k&eFDonM5iFh{^ z;FtT_qYo%x6$`ChDD~;i`c>h@T~X~pZ&-v==wrV4)ra@?=39Z}7c)OR&&9#@9uxU( z?hh)jyY_o}tH;1B>v%95XoGM@gDYB{I@;aJAn;N$2z~uDX|IL`uf-*Mm1ic21|E8c zQZWw`gvb==bz|iv=774j$zii$vlW@T4LDFEfea$Z+frqVA{<)qP_mhp2AbFqEE(0z zfCJgi{n&vKxpSY#-W)(E-Y3u@1KQGcnWN=qz;Nz2-6>bIL8wZk?oy8xe49zo9Evpm zI>QVA&&4C5*aCjxksX%9lfPpQNw|#TzMQ;YvC%Rx=uA#dmU{e@tzaW&rq}9N5VXBw z6Mff^1He^5U}j4TZD};Z7u2!LZ@OjGIPgR|MLZ*9%)E@0nE%K=W5s+NOT~n_{fBc9 z8DlU6un9om`MN~!FtpPXkJSq(+KPHqF&N23_vGeqphc*cEAF=okHGoFWHHWTm&R zAZXR)=q}Jv`jsvKCoL27h?ylNq0fz5xasR{P`5RW_7kzL^b_#T@e?r5nGKuMX?!lz zcEq|hYJscWj{YtO1of8Xi0jH z6s+!rS0;ag(Cml~|NKB+tNwwq9kl+8wc0!T$L$CFw95drNPiuZ3jOf4G_NXoM$sQj zZn*2v3^ISC(OoqO%W>m};%SHDOcD)D7%f&?jnrI9&1_u;6m(x2g#=wb zH$Cl!I6f#QI6iFo2i^nPy^8_Rt0g@Gzv3FoK629)r#wPie#!P^T*B)9JDi>Qta-Ee zyLS}t0#vL+3WcNfUo47o=g+h7Q(waq$0Fo`#^t+!ugP{n=lV`j6a9^vBl)I!L&VaI zK(10FWw?KM*=_ynJ3HIwyD^##=aKUk4u|yIYk$&C>^B?x{I5c+Il`m3RQ%_=Tq`!D zQw3HQ7dw%VR~rkqeqr+THi``YT){njI8j~%3VNWBl3EUyQ zx>y&BaDTkwjg$12&1?kD`IcCB_?j~8XMfHm4iQ(TCj7-)DOn-+%UzP)ab?nnNlfTA zh(FmGsK1tl`G8>eb=1j~9lDZPh<*?zhjW@Gx5%UjcH4 zbrrd<#%%JyFrW`_Loz= zP30^V%kIB;=&%K@{YbXT6@(|c>dXlNk~?15SVEmMX6`Mjv>+MN2M$^N?ju|1T-qoW zJQV;x5rIpTc>eCM*`;fq^U3U2uW>l1RVxe^4B$CEub2J}+bN)$=(gE92((ah@ar_) z+I|k<9;iL6@Dyhc+LX|pTR>r3{P!==s^guY!a#cZ5Ry6QtTzvk zUh~+ICB=TnC(!+~G1}X`=zKbJF=VNy60Le=gO@j5lEJet5>jc!PbM+D!ZlS$KuYx&pkm{S?k)BU1<65@ z({=ySGqzCiV-vc5qOJ z48y)rR(Ys{uWIjyQX*o`4?xK$K9nE1K!t$coI~(ku$IzWaVM`ocnY1)=&_o_R%I_2 zZ_{Cs>@7#7ktZS)0EENs++_HHh39c*#7z#Pyifk3+e!lsET`nm%a#Zp{hflp4Vw$+ zOju*)#0tN99xzE1;G}_c;Oj@<_%Z8;SCB3P74uOYE__wpp<3HB0g0wsxZ1toEwg)5 z23F}NQwRV%3UQi)GQQt^$a%zzV8w>aIl;CkQ!6h%=n!jXPZ;sfULBWNTi1QT%V~R| zdrjBQt+%&EcrjOO0&pO(SR|R1%nis?Q}KUl75Q=`bI5TGenEMls+QNXGp;Grr-EZVy`f(ovFSmI(u6D90n zU}rWOG+9F)ioe9yO)lx~AD<~|_xP=uVs4I z6w+kccIU+(Ltf0bDM$mvJrBdPzjnQ4w#L-qTZ+S6V5l=pqj|%(!m@K!R(Sm5G<;5V zXK~r#d34;M-;>*+VXbyWbw`4vdOanA^uK`Ag&w)G;7}_OpATxWe^GjFe%&*Ocx)w7 zwt4Bs4luF3C-9V+n~E!?(W3d6$CtEn7OZ{~I`6iW|1x;QzkF49GF&d=Wg#fC2^Vn?KLfW@n~pFc4gBpg!U$uFR0 z6`f||PCJat3glNlwW|z^j;^p%9oQc82S&N+!L>xWR*UT~JbFCj)0}2J6c-rV3iVO! z`IdFp zB0H{SvHRu;zx(EM(0%j9fA`HVZ|@5Oo0EGok@w*1K*{Sg3QERYynQ|7kzI{t_?~>T zQGQ|?TPR(EZYAFen;>d7>k zc`O4jwao>J?dp~fG@8l|SBHzOE5h7?Ba_OYs%93|;KP${8}j%VGb?LRi<;yffk06& zmc)TH`g@-+zt@fG!z|MO3057>Y}ppB{w8IS2o68)NnHSA-jKa+X$k+&Klw{5Ksly#ye_HBKV&h1zbIsIT-|0XRq)zWf_~s9{=n3BOfpPy7{f5RZzL^9tdzjj zr)R?-SV}4UX;&dWNKq={6q|g;FEbIjXC}?$K%uY_ur_MF+MkJ>-c@8l1|6F7^BR4N zf%t(1oJ!m zg^z<^ddW{6+A~!=F*1he)s`5=HR&3O@tjq)pn!{ zodn}X=d$=iUh-ibxQ>PQw|#fHTLppRwXG}*HyUkLKB?Vxf>#@2_z&V#B0Cjvmfka$ znI~k?Pp)A)OXy(kdOeH7nbmp9bNb|>|e%T7Dg>BKo&y=JzU)v zs{+P#O$)wko3MOQY!bv_78@Q%uABK!ZPIi<~iCxyQ>J*D53j_;0vks;+?UxqO^ z8)9k;>&t3F)oFofc_t(0cdCn(OIM;4fePgKSw+PKcigoQR9JV_C-y`&%By+|aMjTd z;$iN6>#`KNXtG+yNhfl+PYn(#cr;Nf>DZ1mRU`A-PFI}Scq~0EgRR31c4LZcz_w!3 zU&-x*oGPQoz`-m#bYEC;V<7tHiC(wn395M}YNU9p|6@2$$6(9N_DyMjuOwT6X&Cu> zXg1{_^+%NsBhDf;)3V~J5%bl|^XVjqRgu^moR2288%NOgcLoNBkN6t5F&l2`tPvao zfAbQy!&*Ln*uWc{tVDqwT1{Q>{s19S6+;c@2e$2eZd>zL~I~M}G^8w4Y2bnyq)>=S+L6j%|@%XWqbYm%+}R z%Jg=|X7Y&0*lujN6>tzy)?{CBuT|FT#I=sU+569+)8oyIH?8?{Y{Im(PMHAGs5_GI z>1wLl+yiE$+I28-c2!jx)_?k2nIm}7iH=O{X#yL$s@}hUPf^xece9Vi{DUPRKm%@= zI4q=C$Qla?I0{;1W!^-Bt)o=r>#KNZnZPW3piq_&q`~HLF~1_^MHlt66*62}BJqzu zM;g!LlycVJ?1ohPMvFHu3^-`<`sR(iyLG`EB|;bk%3GG!#?x`m5gx zWnZm7bb@UTrR9OXVs1t)?(5a%Yqq>?ivrob2S7W|CH$C|Kscw z=5hgFRsHTTA{lDQ(a0VW8vk$By+wL4Ao<5{Br)oU$x2pMfJKrlPqr@4P$Y9Nt_7R| zCx>hhMeHtjM0mJ|?T<(EIY{^^cAiA&R=2C=g&o@6vm!E&&86BrLOf18fr==x77OBH zdyOvB1fjqxDMa5;G9@=qu?tN_vB?)=#H^qB;g*jHrr^*ISGt+pLXyWcu+bAWNk&IG zl?zGxV&+)tmQ@d~T5Yypa4*^P5t*t6C($W-Y9zknsGLXPPDR^RF~`>QcV4iB%ltJg#%JgzSOl!L!d<7;Gfa5FAv zjVdBTD(TpZ3>zF8@VbIAM{aYtDv8fh>oAmOoV`*>G_abe#aOPM+6b%!IzPP2K{>A5U*>>2+^+79)a z;+jQ03qhGCNA7Yx7^lX9Ba9FuFHNen`s{buqNeEv)$x#QoePK6M~soRL17NVafu`4RB%F$`Pl z5~X9X{(zDkw(=x-=6pOllhfSrJCozywriAokKZ^VZ?epc?F2YfOmC=V98gW?oL=*# zC!4VJtdyAXwE6cHlNoijVy3KiZxeTrjL5AO4?|IT4#6gV63bUTC!(fd*MK@3^J@F! zOg&Y}^l`KyT>$RnH8O17_%?_PVh?o(+5L|_R7c|c+R_PRXb26L8QM&z+5MaH{wtOk zn}L=^TXs*WwrBLOJ6hDKim{LKAa3?WEiRefh;#TMZ3y1zA%QAUYh={Ux!GU!o~ zQNH$+pUp$BPoB27%q zF^6BflF{;t=SZSz+GrMJ3q~ti7gQ;5SbjS`5!DFxQB8KOt1OQ(G%_V;vcdj>K_dXjNxb}0M?HyjDs(afDCVx%>+I2GAO;jMfy0Iwh$=Utfm z5snMAm4|C3O1?MDEQ%I@RL1I{SrN67(Q)b*7k&Ip+-THJr%-;ILx=v!SaW75@EH3` zUhVOn4CYZ>iZ!iaGNBq9Be`Mcq5Opf?{HZfcJM-VDr$qSCy^3Lij|O&UW{&ffZ&!( zaA9$H9_5lFs;vRx6|mmn{Ic~u%y*(_t~*m12^>%iUOQ9Ap<@`U;!iRpBZ5y=p}@B6 zSP;R6QS{hs7)q75Mgj7814d~Bae=<{A1Z5>;LN66N?m?;5pl?`*_wW1l4a8IBb4tyR6@^@^BOm`{tD6YyAv};)Te2G+K}4;<~T9 ztiHbWTlGjD1=omQ_viT9PJOR7GjZ^{`7u?a_$hGpx54G9Z4Uj-NJ+>3SA0ZSx1vXw zLxYWusP2Sm*#o~_#B)vb&lTfmtsonTnPHIvx!#}HYvp=bPcZe zcHOCWuo0{MxR+#P#Pz1PSlaT$g-HbB!hTlHpV_F!Ay^U-vb1-6W)!xh?3imeOv*Z3 z=D=Ij-4e>!J=_Q#nqT5Fkomgv(@3uQo!?=8R9Sw(0)&ni z2jsV8*xm^OAO91C)$^*!X=%ZHvh_G35URQ9mZ|{A0)E?gJcL0T$H-NA92s6VF$CYW z9RHBse3R!V%B}9#+)P1_9L@j@2VcH-GZ=N2{$k05r?kj$KxpvthW zd7m|F4Ka%sEOHJC`oN z{Q9h2$S$VYkMHBEw7ybMx&7`nIaMLI5n~s)u5f7_tg^|2p4eFF&|6C45|-}T zY2bbCicJ7u0b>nvzMSvbBTOChoOAKvC$b5)Y}lT;{a-@oZBJ!oQNfsC36M4qtjvVR zX;Qkn$Pw56!sOMyw2f6>a4-#^ zy$1D*lt}-KofQ^atUig?;uYP;un=4nq7RPpS6+7^7eT`a+9Hs&(5Wu`IyLv0kJINP zH{2$kHb`Me^3C!975F7KG!qcJ%Ot-tp1f*bJffu1KR9B1lQ=XYBq15?hlJ33*QN-~ z25i$#OI}x{k+-P3EKo3v2XVk4?t;KE4nj1dk!Zo@w6D?!o#k^~T|3?;an*{_dc}rZ zWWWrKbdBu0k$7Zn5A%~0$lei$vU1P?CE&!L*!t%`ziuxu= z$+Xt=qUvFYn;a&JSK-D!mWnDWtF|5q!R|hT$Hv!*O-Hv$ zFMd5*W#~$3AJN-2|IVd@2bWN6TIfD_0uz(~vS50vn&4k2seimRF5`Q+1IS}!NNHN| zuWuQz50#5kO>f(wTSg+{VKXLrOZR$Gm~DhS1f%%-9{FGG$s*ZrqKZL|g5VaRU11N3WB;tGWJx5jj1rPZ1}$YE7~gsu zE25FmauDeN0tjmI!T8LA_@Jktp-r4gQRI3~pz@ext*^u56U%RNNACtB2^N&i&Zkq_ z`%gV|mr`$f?Rog-De|tRlA$9w&gIG-7Zqk}`K~S#ez0!r0TA4$*?1vW^S1eRHim+x~x!Fuo?ZZGGykdj`C(v!pIX!M7^#v%t*g zcznI+6jSi4g8knZOJ2XD^*-Nu8++1xNL67@Dpa}id>w3=oC<2l|TauHqSGbyr z9Lb=M3fe$ymZM2IcIy2$WhWPLfA8YEy!~$2XHICgk})!EbwTa@re-=DC1|8#7fNFq6gJ2K}GKAX`f_@q32jY5x4yTSxUH;`}j*L?c8b@JA9D(4X1n>r5 zmjA{5zUzqX9?77@2f4TGSC#Gv z>RXD%m8Sx#GLz`?10nyLA3f`rKtm)2mp8 z2WUMD#ZK*6rx@tHUO&Z&$15&*p$9S&RarVs7nI?jWCTx!i z0n`(39&^Y>ScN)8+_K-B#JBi}jEM2qqgbCqWKx*4*ll_rs)9n)b|4=f&23 zGJ5Ub{5j_`P?1;gHXtz{3VvNPjI4v63M z7VR-O|JQRM-E&ZagmZ6Y#+`oTU{Zdpg*T>rA?e2lXyimlx-MsB_vpS!^2jDQhm%@q z{n8XwoaYQc8y7Itb%2)$a=$~0tev`)%-s+AXZ8I@XV4DuPx#4Z3^R?1Q&1e*!{+@j zwy0-{m|^s)xqlSU>jQk{owo@5+inF)-p_24DlAw`pUe~G8ATB<-h>G97|FK_kfkQlN-!Xir7CB=dF)cJj`)++W>CeZ z0KpG5Ul%&-7q_N%mRtvtM37+jS>A#7p`RadxDFCIFsAEA)28 zRc#)^^3Z1>`W_P8_n+_5l5pGfayTk_=7^k}d#ir!c>8mR4k$J+> z7$;sN^3k#e1A<-CaO6F6V7^1u(puc4hVnfPK2u$wSE_XF>^Bp?OAv{2Y8)b{(a(2LFQfe!w)T1x>k{ZpuhTF(Y6rhpZbrH!ElxM! z5seXw{2(-vFEyNn8P2QzldxYgR;$=9Va+n>oR-HQXL;u7|E|m|OuX!t) z=Y4P{a-kdSJHXaCvpi=8=DW$Bomevgq&Ys4T71MX_~k_QpcOJ7j|>5e z8fKax8KCNY#00?1+;-F_`mYl6?wiA0M9-%AWH7g{~~uALu>r1q7;w|*!aJIeE{mR8WtR@KBhs8TcC2jA=CW|Xy-ycIi>d)c7Okmo?_;IS6kWJ z(`FLRj~hxiQw>hGi`}`RB+q+jpRWZ9z114q7dyj#>yMG?n=NfcSz}CGOi5Bt#D4u( zFREX`PCs3=cqxne=H=$udT;=|-YI7ij;hPlH)3oXm z`Zikh-OIS^*V9YKw;%r4iW?YA#ppM%LKP=jnMYQ)JEBqy1t4U@E<8VwMW2U*KvaS5 zNDwVyHjTg6hvcbS>{N7lJu=~^Ut)S#sq~v9%#hIV2H~>o^9=!kEGypac0E4e6TQIW zr~+Bn`Sb4k*0*Zts;f;Vq@fsZn1hLBQyIO8W(13u0211vHK)RMC5neH4xx7?6jMVOl3i-ENH1NU{ z-FW1hXwfmWi;TOg`k_dSL1ckNlukjE5IiKg=2DaEcWG#qTCd+ts`vavz;Wye>fPE6 zy5Y~H#6~R#r29XgZcKEUWF`#TkPjT0Tb$nr`$rM*rO!0=z{AwY-%*%Y>1iy07;xo= zlqRRR7Oc25bnNStf}IG@3`}b^k0oTD!zg(19YJjRnXs}9jracK>Fw6_hgpNk9M$d_ zY;%@p@*94vn6~^S;rS|c_SBN9%41Y5CNDz~xgJ>zs5bOlC^*0Hm`3d+UdEAQlhAJ~ z9rS!JpiEjf-g5TxWc*_}=Uu;kRBG#hg)R{HVt_KfnWZwXW)vK%qN^F`Uk1yRWlJX^%Xv zrk4pFBKoY0c4V8}-7;k5jeHn#no6bE=CpUiQ*YjAXr&^e4Ji=kd5l#`F`6lq$7V{v z3HxGM@4$C!_rCJ0-}}J#b+>i@#M5T@ zDq!my3QKfc?}%tQt*O2KZN233YvPN6nJ}^KNmAv>Z%4u&!~ecZRVXA}Vl6Juc1QC% z^+u0V1RbM%wwc6J;|v%G|8k{t}#XaV3b2aS>;{E0?a{QN?D zjap1}Foj*+4gOfLe03+j+-fGX6EVmh%q%{kCs18^=Y$ttM`Ru~Sih(@mxvo*(|OHJwq(zE2(ex%#gkzo*Y14gL&0 zb&R`Soa5K^wB%jo6cc>zQGL@J1IWOVy&G6nrZ5tClv8t|5cv^+Gb2^+T0kC3kdVb= zzt>d9Y8%qhJjVP{A;^*2E;@stxE=CCM8#hlN3jEzVQ}z~l*fFX-3jF?-%dnrKMp>* z+*ojsjy{>@Jvb5ZmHokSc4fmUNZRBEvkDd^(WV&AoGicLZM&xx+F?MzT8H=FtNK9| zS}XSejv}P(R*P5=IL)L^{d8bx{SC>9DDxXj4@z-n^Hya-p}k%LC>kvh2A}eK-{n8P z{ymeI^r5$}WuJ`hTT7y&m(wGugFoqC45jML$-|3L7JDo`mbG@4AeOa9^F5Xfc~AdJ z6z*HExRMYeE;qZsGE(eCPFCa$fMk$Uzn)5Lqpt$(K3(+J)whl&sJ0{&+hDO7rV zmH=Vx#~{t)BZI;GL9NP4eoCJAPi}V8s2_pM0^Qn!dLjeT+!j52$p%MSaS9-1=VIXE zZZI?CV3-Z~UNNk|?P_bEXiaFvcS$(=j(imNA_Txz*qk*3Zt> zNTsgN3vU6G(NEuWibkSSE-gZ&wr@}`tuvHEIJGFQY)vT7_Sn%Zf>;noCdR{II*9Uy zi1DPT!QZt9edc?XCO_%vF)Vha6tK-jiPV+wdZr2-8Z+moIE4fA9Um2wrmprd`ujDw zA4$!<#8*6C%(UP!wX!r@9XeCS{UX~rhBT6- z&m5@`REID~K)qRRLN40)>Fz=?P=C-jXZA1}lMo#Lic@|(zYtC?Sr$}gjz;wX-)dH; z>kQvsjFQ|FEvL5r4GE`Vi>HJ+qxMkQH`jx)M#C81t{fBmVaUEu2p_>}$^Lp*OiKYZg_C_ycw2+?0OT`)la$oyQwx zn_edD@HInp4-Gny;i{I~SnCp_RpFSS_!Eo_CI3DYHotlBCu`)~d17BV58M;K#oqAY zMpX+Xw9;xj#wpOozs(lT<+Th^5&14m(|Q*%;z`vKh4SNgAVBe}N~g2sLPrFC2|fE< zFpnnM-xp>{8@7DssTYKd@0S%KXilVkqrjiHGyiM<4X=4ToUoPe$O?bRyn$W!y*w+D z6&Dp2t9Ct*jrJO53Vv$UzniUP=-;pr=_NhmXKlFLRkmbSfW7QwHhvWb87Y|_ zx8ovSSXKm9h{zGnW$Hh-iI?ZMHSbjn*3Sh{-$#hX$;rQovTb9bL)q_$Wc zZmKiDhCM5p5vXSn($(MVPz`Tl^8Dq9O!MXzxdIh}Yi;I?zh>o(TXxwNlF}fbbJWC- z#GcWxTx796z)2UUjk&XWZFb3^oh-r)7Kkx{urkexT2D1!HLjPN~zvz2X#hz4#kSWLV*CW#DJu#do;exLU5E*Yb2H*HhXE&}5w)`L0O>xl{F?nRCT2 z*sv_q70&aZdR}eGSdA;#MccWyIlME%-v<$!Uv*^qnA&%(krwShZthK$iyit6H#l;> zK-^@!-w;mtEMfj7rnxx}?MKV=JHn^z-cHiGPN(d-mV0j(9hnwwg#l4%su_AWn&D=e zjR-cx9)55a@TwJcUi!8R@A2vD&T99g^diZcn-!n?8)u3269>8(cQRcMciiUGO^eip z5B)0E8kXbcz#sx*&|^TUl$Lb)lb&Ip>#TdtDfUcwzE~nzmuQ7EmTjAgdgUiGuSuNa zpCb6rE6(O5o(^pW-+RuE)g@nrZK=PFeQcL58r8o>9J$FQ<9+2A1d*DBdQ!b*dT;;4 z$Xo4EWN=S2^E$tAy9hSL=6Vn#bHD2g;0=sNhjJ6d)KUocZ)+A6o6_A*qTK}$*h#RS zyk#XkuOO@^1ht8v-%9N{Y9oewzu$e7L(scb^mXW2_TiW*-y)vNyH`OadIrI^Y>*Zd zp?=ROXFoq0Kk^tpwCFt$B)QKsZPM$&nJ*fs2;Xd)FtPd@FMUTnfVUp;sJHFaw;TuBTKR%BOW_}ClL_Bhz{A0l{Qgc%@tjIWj2ys8T z-56z(;=%E*LE!6!#2)6$>Eq4>1p;7`)Z_NSc1X=l%@0`gB7usIOR#p2{Cap%H#@u+ z`w+GL;VMer0DCjGMC|TGF_;&EgwZvSq=Q8@4}X7rF+n51h%CM@hl5WX$J z1a?I~km{+qh|RA-3+BNxgHjmg>KA!Bo!rA$QbB?cckI}KdkcLRox3JZd`fkXjx#A+ z_&En<1xc&Qmnoz0c*OV_guW?$J#uUHP(jS@beks0sZ#) z21ebzv6U?Wp@^S4Wn-$u_zmK3cE*C1Mlc5xAi|J_lu9>vY@H z+=VfBpk=&5g2V=pY;m2PHSN1`4hDAzs43VInEYm~-~S`AxRI%f?TU84wXtx z=s<1xk#OUIW)~ZG_2?E}ncAz?RlZ%Nu{wqJtc71aL~G>$Y^@Cl^I zh)|w&6EwGxERMm32{6|adN{lmCnO=?!|jUP3Ws1;e!SWGzjeq)Lvs!ZTTq&ie5vo- z`1p%Yqwt8KsRfc+Zbj`#L-1}(Bwi~Ax5qO&ZU@{ejQ+Hp4mt4VPoV_VeCr(6zF z9UR1ae&+2iX+s6E2V}Lxc6ZM+-8S6$a@?&Cn^C~=sPX~d#JLm;5Qw1n%IW*&PBV?q z09O(5{}gEc5xG_jOowcjF=x4y(&YamY5r}Y`?S#80Bh&J&-}>XgL{roRVEZo{x*i~ ziq&;TCj2%^Ju@%&4lTnyhe)5-5PDrQb*+9kAHW!EOaiu61g8cl_=CS1bA@HjhP}H5 zEBJUSKy2WF;ua_T{{-d-8TdvHidCA`BXq&j4cFtL z^yXVy20#nD1@%y@Y5U4sF1MvXa8K;F7B|Z;gH>tspveGY5S|}@U_A#|Imi?6GS1f%=ROP|BEkV#WqVG3b_;n2 z;H#;^adfh%ovD>w5Gs4>tI$7iJW3x%2mWus`fl%IFZf2qhN?JgWZYM_WBdsAyZ9Ln zRkEUt($@b`?c4fgl`7mn2lzu)}t zF)QPs=rMRr?Dp9+=yMv@`)?NKswHtVMS+34S>A@W)D9NFirDEhF)P8UhG0LzO-*O0 zw~iYtAHX;-bhAs~r#R<26~a<=Te-BB1z_}yavF7s_X>@Au~8kI-fv?*ch&2-MEDeRpn$| zQs#J6{sP}E#c@zKLH{=n*1NNgxp^;34)cyq+y$_nMaXHdPefdQB&ZYuaBF&F+#jI) z5iI(HZ*=0~V#^Xg^oqt{LGBS3`Mzzz-b6=qrl1#6B|u? z)MRjg9LIM9!?@uFajP;=#Ssg@2~wUs91pUhTWF1+X;!z;#!7zZ!HA3(S&VVh0-H-7)D5Ez?jhb5*13LRK%!y+ z0JbakM=Tfr@d$}P-7SM{#QqrU2pOeg#laPR_u*ECoxGxwD+5qp7mJFAC4KD`kx<@y z!H-TwF(`nXfja!2zxynS|Kfw?Nv{=+iYwx~iR_4 zsDFPJT72Tn&;L~mWIpqIHR?q6{H5=03xogjIQ00LT=Sm?Yu??dTo^X%GTU3y3 z5U%wt^lQ~lI;@oqpCR=JSG?o&&sGC)JkTBL$iPQn)gVhj=u1Ww=)nAbnfA|CTF1W} zHDFT%X57(fTIQ+HQ=ZLM-4b?z)=H^8gSHr jqXrx`;HZHtT?79Qd=?ufS>7*000000NkvXXu0mjfyH5ns literal 0 HcmV?d00001 diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval.c new file mode 100644 index 00000000..d9f4407c --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval.c @@ -0,0 +1,1371 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval.c + * @author MCD Application Team + * @brief This file provides a set of firmware functions to manage LEDs, + * push-buttons and COM ports available on STM32F769I-EVAL + * evaluation board(MB1219) from STMicroelectronics. + * + @verbatim + This driver requires the stm32f769i_eval_io.c/.h files to manage the + IO module resources mapped on the MFX IO expander. + These resources are mainly LEDs, Joystick push buttons, SD detect pin, + USB OTG power switch/over current drive pins, Camera plug pin, Audio + INT pin + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f769i_eval_io.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_uart.c +- stm32f7xx_hal_i2c.c +- stm32f7xx_hal_adc.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval.h" +#if defined(USE_IOEXPANDER) +#include "stm32f769i_eval_io.h" +#endif /* USE_IOEXPANDER */ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_LOW_LEVEL STM32F769I_EVAL LOW LEVEL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_LOW_LEVEL_Private_TypesDefinitions STM32F769I-EVAL LOW LEVEL Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LOW_LEVEL_Private_Defines STM32F769I-EVAL LOW LEVEL Private Defines + * @{ + */ +/** + * @brief STM32F769I EVAL BSP Driver version number V2.0.2 + */ +#define __STM32F769I_EVAL_BSP_VERSION_MAIN (0x02) /*!< [31:24] main version */ +#define __STM32F769I_EVAL_BSP_VERSION_SUB1 (0x00) /*!< [23:16] sub1 version */ +#define __STM32F769I_EVAL_BSP_VERSION_SUB2 (0x02) /*!< [15:8] sub2 version */ +#define __STM32F769I_EVAL_BSP_VERSION_RC (0x00) /*!< [7:0] release candidate */ +#define __STM32F769I_EVAL_BSP_VERSION ((__STM32F769I_EVAL_BSP_VERSION_MAIN << 24)\ + |(__STM32F769I_EVAL_BSP_VERSION_SUB1 << 16)\ + |(__STM32F769I_EVAL_BSP_VERSION_SUB2 << 8 )\ + |(__STM32F769I_EVAL_BSP_VERSION_RC)) +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LOW_LEVEL_Private_Macros STM32F769I-EVAL LOW LEVEL Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LOW_LEVEL_Private_Variables STM32F769I-EVAL LOW LEVEL Private Variables + * @{ + */ +GPIO_TypeDef* GPIO_PORT[LEDn] = {LED1_GPIO_PORT, + LED2_GPIO_PORT, + LED3_GPIO_PORT, + LED4_GPIO_PORT}; + +const uint32_t GPIO_PIN[LEDn] = {LED1_PIN, + LED2_PIN, + LED3_PIN, + LED4_PIN}; + +GPIO_TypeDef* BUTTON_PORT[BUTTONn] = {WAKEUP_BUTTON_GPIO_PORT, + TAMPER_BUTTON_GPIO_PORT, + KEY_BUTTON_GPIO_PORT}; + +const uint16_t BUTTON_PIN[BUTTONn] = {WAKEUP_BUTTON_PIN, + TAMPER_BUTTON_PIN, + KEY_BUTTON_PIN}; + +const uint16_t BUTTON_IRQn[BUTTONn] = {WAKEUP_BUTTON_EXTI_IRQn, + TAMPER_BUTTON_EXTI_IRQn, + KEY_BUTTON_EXTI_IRQn}; + +USART_TypeDef* COM_USART[COMn] = {EVAL_COM1}; + +GPIO_TypeDef* COM_TX_PORT[COMn] = {EVAL_COM1_TX_GPIO_PORT}; + +GPIO_TypeDef* COM_RX_PORT[COMn] = {EVAL_COM1_RX_GPIO_PORT}; + +const uint16_t COM_TX_PIN[COMn] = {EVAL_COM1_TX_PIN}; + +const uint16_t COM_RX_PIN[COMn] = {EVAL_COM1_RX_PIN}; + +const uint16_t COM_TX_AF[COMn] = {EVAL_COM1_TX_AF}; + +const uint16_t COM_RX_AF[COMn] = {EVAL_COM1_RX_AF}; + +static I2C_HandleTypeDef hEvalI2c; +static ADC_HandleTypeDef hEvalADC; + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LOW_LEVEL_Private_FunctionPrototypes STM32F769I_EVAL LOW LEVEL Private Function Prototypes + * @{ + */ +static void I2Cx_MspInit(void); +static void I2Cx_Init(void); +static void I2Cx_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +static uint8_t I2Cx_Read(uint8_t Addr, uint8_t Reg); +static HAL_StatusTypeDef I2Cx_ReadMultiple(uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static HAL_StatusTypeDef I2Cx_WriteMultiple(uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length); +static HAL_StatusTypeDef I2Cx_IsDeviceReady(uint16_t DevAddress, uint32_t Trials); +static void I2Cx_Error(uint8_t Addr); + +#if defined(USE_IOEXPANDER) +/* IOExpander IO functions */ +void IOE_Init(void); +void IOE_ITConfig(void); +void IOE_Delay(uint32_t Delay); +void IOE_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +uint8_t IOE_Read(uint8_t Addr, uint8_t Reg); +uint16_t IOE_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); +void IOE_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); + +/* MFX IO functions */ +void MFX_IO_Init(void); +void MFX_IO_DeInit(void); +void MFX_IO_ITConfig(void); +void MFX_IO_Delay(uint32_t Delay); +void MFX_IO_Write(uint16_t Addr, uint8_t Reg, uint8_t Value); +uint8_t MFX_IO_Read(uint16_t Addr, uint8_t Reg); +uint16_t MFX_IO_ReadMultiple(uint16_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); +void MFX_IO_Wakeup(void); +void MFX_IO_EnableWakeupPin(void); +#endif /* USE_IOEXPANDER */ + +/* AUDIO IO functions */ +void AUDIO_IO_Init(void); +void AUDIO_IO_DeInit(void); +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value); +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg); +void AUDIO_IO_Delay(uint32_t Delay); + +/* CAMERA IO functions */ +void CAMERA_IO_Init(void); +void CAMERA_Delay(uint32_t Delay); +void CAMERA_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value); +uint16_t CAMERA_IO_Read(uint8_t Addr, uint16_t Reg); + +/* I2C EEPROM IO function */ +void EEPROM_IO_Init(void); +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials); + +/* TouchScreen (TS) IO functions */ +void TS_IO_Init(void); +void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg); +uint16_t TS_IO_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); +void TS_IO_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length); +void TS_IO_Delay(uint32_t Delay); + +#if defined(USE_LCD_HDMI) +/* HDMI IO functions */ +void HDMI_IO_Init(void); +void HDMI_IO_Delay(uint32_t Delay); +void HDMI_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); +uint8_t HDMI_IO_Read(uint8_t Addr, uint8_t Reg); +#endif /* USE_LCD_HDMI */ + +void OTM8009A_IO_Delay(uint32_t Delay); +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LOW_LEVEL_Private_Functions STM32F769I_EVAL LOW LEVEL Private Functions + * @{ + */ + + /** + * @brief This method returns the STM32F769I EVAL BSP Driver revision + * @retval version: 0xXYZR (8bits for each decimal, R for RC) + */ +uint32_t BSP_GetVersion(void) +{ + return __STM32F769I_EVAL_BSP_VERSION; +} + +/** + * @brief Configures LED on GPIO and/or on MFX. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @arg LED3 + * @arg LED4 + * @retval None + */ +void BSP_LED_Init(Led_TypeDef Led) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /* Enable the GPIO_LED clock */ + LEDx_GPIO_CLK_ENABLE(Led); + + /* Configure the GPIO_LED pin */ + GPIO_InitStruct.Pin = GPIO_PIN[Led]; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + + HAL_GPIO_Init(GPIO_PORT[Led], &GPIO_InitStruct); + + /* By default, turn off LED */ + HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_SET); +} + + +/** + * @brief DeInit LEDs. + * @param Led: LED to be configured. + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @arg LED3 + * @arg LED4 + * @note Led DeInit does not disable the GPIO clock nor disable the Mfx + * @retval None + */ +void BSP_LED_DeInit(Led_TypeDef Led) +{ + /* Turn off LED */ + HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_RESET); + /* Configure the GPIO_LED pin */ + HAL_GPIO_DeInit(GPIO_PORT[Led], GPIO_PIN[Led]); +} + +/** + * @brief Turns selected LED On. + * @param Led: LED to be set on + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @arg LED3 + * @arg LED4 + * @retval None + */ +void BSP_LED_On(Led_TypeDef Led) +{ + HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_RESET); +} + +/** + * @brief Turns selected LED Off. + * @param Led: LED to be set off + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @arg LED3 + * @arg LED4 + * @retval None + */ +void BSP_LED_Off(Led_TypeDef Led) +{ + HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_SET); +} + +/** + * @brief Toggles the selected LED. + * @param Led: LED to be toggled + * This parameter can be one of the following values: + * @arg LED1 + * @arg LED2 + * @arg LED3 + * @arg LED4 + * @retval None + */ +void BSP_LED_Toggle(Led_TypeDef Led) +{ + HAL_GPIO_TogglePin(GPIO_PORT[Led], GPIO_PIN[Led]); +} + +/** + * @brief Configures button GPIO and EXTI Line. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_TAMPER: Tamper Push Button + * @arg BUTTON_KEY: Key Push Button + * @param ButtonMode: Button mode + * This parameter can be one of the following values: + * @arg BUTTON_MODE_GPIO: Button will be used as simple IO + * @arg BUTTON_MODE_EXTI: Button will be connected to EXTI line + * with interrupt generation capability + * @note On STM32F769I-EVAL evaluation board, the three buttons (Wakeup, Tamper + * and key buttons) are mapped on the same push button named "Wakeup/Tamper" + * on the board serigraphy. + * @retval None + */ +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef ButtonMode) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /* Enable the BUTTON clock */ + BUTTONx_GPIO_CLK_ENABLE(Button); + + if(ButtonMode == BUTTON_MODE_GPIO) + { + /* Configure Button pin as input */ + GPIO_InitStruct.Pin = BUTTON_PIN[Button]; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(BUTTON_PORT[Button], &GPIO_InitStruct); + } + + if(ButtonMode == BUTTON_MODE_EXTI) + { + /* Configure Button pin as input with External interrupt */ + GPIO_InitStruct.Pin = BUTTON_PIN[Button]; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + + if(Button != BUTTON_WAKEUP) + { + GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; + } + else + { + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; + } + + HAL_GPIO_Init(BUTTON_PORT[Button], &GPIO_InitStruct); + + /* Enable and set Button EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(BUTTON_IRQn[Button]), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + } +} + +/** + * @brief Push Button DeInit. + * @param Button: Button to be configured + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_TAMPER: Tamper Push Button + * @arg BUTTON_KEY: Key Push Button + * @note On STM32F769I-EVAL evaluation board, the three buttons (Wakeup, Tamper + * and key buttons) are mapped on the same push button named "Wakeup/Tamper" + * on the board serigraphy. + * @note PB DeInit does not disable the GPIO clock + * @retval None + */ +void BSP_PB_DeInit(Button_TypeDef Button) +{ + GPIO_InitTypeDef gpio_init_structure; + + gpio_init_structure.Pin = BUTTON_PIN[Button]; + HAL_NVIC_DisableIRQ((IRQn_Type)(BUTTON_IRQn[Button])); + HAL_GPIO_DeInit(BUTTON_PORT[Button], gpio_init_structure.Pin); +} + + +/** + * @brief Returns the selected button state. + * @param Button: Button to be checked + * This parameter can be one of the following values: + * @arg BUTTON_WAKEUP: Wakeup Push Button + * @arg BUTTON_TAMPER: Tamper Push Button + * @arg BUTTON_KEY: Key Push Button + * @note On STM32F769I-EVAL evaluation board, the three buttons (Wakeup, Tamper + * and key buttons) are mapped on the same push button named "Wakeup/Tamper" + * on the board serigraphy. + * @retval The Button GPIO pin value + */ +uint32_t BSP_PB_GetState(Button_TypeDef Button) +{ + return HAL_GPIO_ReadPin(BUTTON_PORT[Button], BUTTON_PIN[Button]); +} + +/** + * @brief Configures COM port. + * @param COM: COM port to be configured. + * This parameter can be one of the following values: + * @arg COM1 + * @arg COM2 + * @param huart: Pointer to a UART_HandleTypeDef structure that contains the + * configuration information for the specified USART peripheral. + * @retval None + */ +void BSP_COM_Init(COM_TypeDef COM, UART_HandleTypeDef *huart) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable GPIO clock */ + EVAL_COMx_TX_GPIO_CLK_ENABLE(COM); + EVAL_COMx_RX_GPIO_CLK_ENABLE(COM); + + /* Enable USART clock */ + EVAL_COMx_CLK_ENABLE(COM); + + /* Configure USART Tx as alternate function */ + gpio_init_structure.Pin = COM_TX_PIN[COM]; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Alternate = COM_TX_AF[COM]; + HAL_GPIO_Init(COM_TX_PORT[COM], &gpio_init_structure); + + /* Configure USART Rx as alternate function */ + gpio_init_structure.Pin = COM_RX_PIN[COM]; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Alternate = COM_RX_AF[COM]; + HAL_GPIO_Init(COM_RX_PORT[COM], &gpio_init_structure); + + /* USART configuration */ + huart->Instance = COM_USART[COM]; + HAL_UART_Init(huart); +} + +/** + * @brief DeInit COM port. + * @param COM: COM port to be configured. + * This parameter can be one of the following values: + * @arg COM1 + * @arg COM2 + * @param huart: Pointer to a UART_HandleTypeDef structure that contains the + * configuration information for the specified USART peripheral. + * @retval None + */ +void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart) +{ + /* USART configuration */ + huart->Instance = COM_USART[COM]; + HAL_UART_DeInit(huart); + + /* Enable USART clock */ + EVAL_COMx_CLK_DISABLE(COM); + + /* DeInit GPIO pins can be done in the application + (by surcharging this __weak function) */ + + /* GPIO pins clock, DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Init Potentiometer. + * @retval None + */ +void BSP_POTENTIOMETER_Init(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + ADC_ChannelConfTypeDef ADC_Config; + + /* ADC an GPIO Periph clock enable */ + ADCx_CLK_ENABLE(); + ADCx_CHANNEL_GPIO_CLK_ENABLE(); + + /* ADC Channel GPIO pin configuration */ + GPIO_InitStruct.Pin = ADCx_CHANNEL_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(ADCx_CHANNEL_GPIO_PORT, &GPIO_InitStruct); + + /* Configure the ADC peripheral */ + hEvalADC.Instance = ADCx; + + HAL_ADC_DeInit(&hEvalADC); + + hEvalADC.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4; /* Asynchronous clock mode, input ADC clock not divided */ + hEvalADC.Init.Resolution = ADC_RESOLUTION_12B; /* 12-bit resolution for converted data */ + hEvalADC.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* Right-alignment for converted data */ + hEvalADC.Init.ScanConvMode = DISABLE; /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */ + hEvalADC.Init.EOCSelection = DISABLE; /* EOC flag picked-up to indicate conversion end */ + hEvalADC.Init.ContinuousConvMode = DISABLE; /* Continuous mode disabled to have only 1 conversion at each conversion trig */ + hEvalADC.Init.NbrOfConversion = 1; /* Parameter discarded because sequencer is disabled */ + hEvalADC.Init.DiscontinuousConvMode = DISABLE; /* Parameter discarded because sequencer is disabled */ + hEvalADC.Init.NbrOfDiscConversion = 0; /* Parameter discarded because sequencer is disabled */ + hEvalADC.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; /* Software start to trig the 1st conversion manually, without external event */ + hEvalADC.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Parameter discarded because software trigger chosen */ + hEvalADC.Init.DMAContinuousRequests = DISABLE; /* DMA one-shot mode selected */ + + + HAL_ADC_Init(&hEvalADC); + + /* Configure ADC regular channel */ + ADC_Config.Channel = ADCx_CHANNEL; /* Sampled channel number */ + ADC_Config.Rank = 1; /* Rank of sampled channel number ADCx_CHANNEL */ + ADC_Config.SamplingTime = ADC_SAMPLETIME_3CYCLES; /* Sampling time (number of clock cycles unit) */ + ADC_Config.Offset = 0; /* Parameter discarded because offset correction is disabled */ + + HAL_ADC_ConfigChannel(&hEvalADC, &ADC_Config); +} + +/** + * @brief Get Potentiometer level in 12 bits. + * @retval Potentiometer level(0..0xFFF) / 0xFFFFFFFF : Error + */ +uint32_t BSP_POTENTIOMETER_GetLevel(void) +{ + if(HAL_ADC_Start(&hEvalADC) == HAL_OK) + { + if(HAL_ADC_PollForConversion(&hEvalADC, ADCx_POLL_TIMEOUT)== HAL_OK) + { + return (HAL_ADC_GetValue(&hEvalADC)); + } + } + return 0xFFFFFFFF; +} + +#if defined(USE_IOEXPANDER) +/** + * @brief Configures joystick GPIO and EXTI modes. + * @param JoyMode: Button mode. + * This parameter can be one of the following values: + * @arg JOY_MODE_GPIO: Joystick pins will be used as simple IOs + * @arg JOY_MODE_EXTI: Joystick pins will be connected to EXTI line + * with interrupt generation capability + * @retval IO_OK: if all initializations are OK. Other value if error. + */ +uint8_t BSP_JOY_Init(JOYMode_TypeDef JoyMode) +{ + uint8_t ret = 0; + + /* Initialize the IO functionalities */ + ret = BSP_IO_Init(); + + /* Configure joystick pins in IT mode */ + if(JoyMode == JOY_MODE_EXTI) + { + /* Configure IO interrupt acquisition mode */ + BSP_IO_ConfigPin(JOY_ALL_PINS, IO_MODE_IT_LOW_LEVEL_PU); + } + else + { + BSP_IO_ConfigPin(JOY_ALL_PINS, IO_MODE_INPUT_PU); + } + + return ret; +} + + +/** + * @brief DeInit joystick GPIOs. + * @note JOY DeInit does not disable the MFX, just set the MFX pins in Off mode + * @retval None. + */ +void BSP_JOY_DeInit() +{ + BSP_IO_ConfigPin(JOY_ALL_PINS, IO_MODE_OFF); +} + +/** + * @brief Returns the current joystick status. + * @retval Code of the joystick key pressed + * This code can be one of the following values: + * @arg JOY_NONE + * @arg JOY_SEL + * @arg JOY_DOWN + * @arg JOY_LEFT + * @arg JOY_RIGHT + * @arg JOY_UP + */ +JOYState_TypeDef BSP_JOY_GetState(void) +{ + uint16_t pin_status = 0; + + /* Read the status joystick pins */ + pin_status = BSP_IO_ReadPin(JOY_ALL_PINS); + + /* Check the pressed keys */ + if((pin_status & JOY_NONE_PIN) == JOY_NONE) + { + return(JOYState_TypeDef) JOY_NONE; + } + else if(!(pin_status & JOY_SEL_PIN)) + { + return(JOYState_TypeDef) JOY_SEL; + } + else if(!(pin_status & JOY_DOWN_PIN)) + { + return(JOYState_TypeDef) JOY_DOWN; + } + else if(!(pin_status & JOY_LEFT_PIN)) + { + return(JOYState_TypeDef) JOY_LEFT; + } + else if(!(pin_status & JOY_RIGHT_PIN)) + { + return(JOYState_TypeDef) JOY_RIGHT; + } + else if(!(pin_status & JOY_UP_PIN)) + { + return(JOYState_TypeDef) JOY_UP; + } + else + { + return(JOYState_TypeDef) JOY_NONE; + } +} + +#endif /* USE_IOEXPANDER */ + +/******************************************************************************* + BUS OPERATIONS +*******************************************************************************/ + +/******************************* I2C Routines *********************************/ +/** + * @brief Initializes I2C MSP. + * @retval None + */ +static void I2Cx_MspInit(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + EVAL_I2Cx_SCL_SDA_GPIO_CLK_ENABLE(); + + /* Configure I2C Tx as alternate function */ + gpio_init_structure.Pin = EVAL_I2Cx_SCL_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_OD; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; + gpio_init_structure.Alternate = EVAL_I2Cx_SCL_SDA_AF; + HAL_GPIO_Init(EVAL_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /* Configure I2C Rx as alternate function */ + gpio_init_structure.Pin = EVAL_I2Cx_SDA_PIN; + HAL_GPIO_Init(EVAL_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure); + + /*** Configure the I2C peripheral ***/ + /* Enable I2C clock */ + EVAL_I2Cx_CLK_ENABLE(); + + /* Force the I2C peripheral clock reset */ + EVAL_I2Cx_FORCE_RESET(); + + /* Release the I2C peripheral clock reset */ + EVAL_I2Cx_RELEASE_RESET(); + + /* Enable and set I2Cx Interrupt to a lower priority */ + HAL_NVIC_SetPriority(EVAL_I2Cx_EV_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(EVAL_I2Cx_EV_IRQn); + + /* Enable and set I2Cx Interrupt to a lower priority */ + HAL_NVIC_SetPriority(EVAL_I2Cx_ER_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(EVAL_I2Cx_ER_IRQn); +} + +/** + * @brief Initializes I2C HAL. + * @retval None + */ +static void I2Cx_Init(void) +{ + if(HAL_I2C_GetState(&hEvalI2c) == HAL_I2C_STATE_RESET) + { + hEvalI2c.Instance = EVAL_I2Cx; + hEvalI2c.Init.Timing = EVAL_I2Cx_TIMING; + hEvalI2c.Init.OwnAddress1 = 0; + hEvalI2c.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + hEvalI2c.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + hEvalI2c.Init.OwnAddress2 = 0; + hEvalI2c.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + hEvalI2c.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + + /* Init the I2C */ + I2Cx_MspInit(); + HAL_I2C_Init(&hEvalI2c); + } +} + +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Value: Data to be written + * @retval None + */ +static void I2Cx_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Write(&hEvalI2c, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, &Value, 1, 100); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* Execute user timeout callback */ + I2Cx_Error(Addr); + } +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Register address + * @retval Read data + */ +static uint8_t I2Cx_Read(uint8_t Addr, uint8_t Reg) +{ + HAL_StatusTypeDef status = HAL_OK; + uint8_t Value = 0; + + status = HAL_I2C_Mem_Read(&hEvalI2c, Addr, Reg, I2C_MEMADD_SIZE_8BIT, &Value, 1, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* Execute user timeout callback */ + I2Cx_Error(Addr); + } + return Value; +} + +/** + * @brief Reads multiple data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param MemAddress: internal memory address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval Number of read data + */ +static HAL_StatusTypeDef I2Cx_ReadMultiple(uint8_t Addr, uint16_t Reg, uint16_t MemAddress, uint8_t *Buffer, uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Read(&hEvalI2c, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* I2C error occurred */ + I2Cx_Error(Addr); + } + return status; +} + +/** + * @brief Writes a value in a register of the device through BUS in using DMA mode. + * @param Addr: Device address on BUS Bus. + * @param Reg: The target register address to write + * @param MemAddress: internal memory address + * @param Buffer: The target register value to be written + * @param Length: buffer size to be written + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_WriteMultiple(uint8_t Addr, uint16_t Reg, uint16_t MemAddress, uint8_t *Buffer, uint16_t Length) +{ + HAL_StatusTypeDef status = HAL_OK; + + status = HAL_I2C_Mem_Write(&hEvalI2c, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000); + + /* Check the communication status */ + if(status != HAL_OK) + { + /* Re-Initiaize the I2C Bus */ + I2Cx_Error(Addr); + } + return status; +} + +/** + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param DevAddress: Target device address + * @param Trials: Number of trials + * @retval HAL status + */ +static HAL_StatusTypeDef I2Cx_IsDeviceReady(uint16_t DevAddress, uint32_t Trials) +{ + return (HAL_I2C_IsDeviceReady(&hEvalI2c, DevAddress, Trials, 1000)); +} + +/** + * @brief Manages error callback by re-initializing I2C. + * @param Addr: I2C Address + * @retval None + */ +static void I2Cx_Error(uint8_t Addr) +{ + /* De-initialize the I2C communication bus */ + HAL_I2C_DeInit(&hEvalI2c); + + /* Re-Initialize the I2C communication bus */ + I2Cx_Init(); +} + +/******************************************************************************* + LINK OPERATIONS +*******************************************************************************/ + +/********************************* LINK IOE ***********************************/ +#if defined(USE_IOEXPANDER) +/** + * @brief Initializes IOE low level. + * @retval None + */ +void IOE_Init(void) +{ + I2Cx_Init(); +} + +/** + * @brief Configures IOE low level interrupt. + * @retval None + */ +void IOE_ITConfig(void) +{ + /* IO expander IT config done by BSP_TS_ITConfig function */ +} + +/** + * @brief IOE writes single data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Value: Data to be written + * @retval None + */ +void IOE_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_Write(Addr, Reg, Value); +} + +/** + * @brief IOE reads single data. + * @param Addr: I2C address + * @param Reg: Register address + * @retval Read data + */ +uint8_t IOE_Read(uint8_t Addr, uint8_t Reg) +{ + return I2Cx_Read(Addr, Reg); +} + +/** + * @brief IOE reads multiple data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval Number of read data + */ +uint16_t IOE_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + return I2Cx_ReadMultiple(Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief IOE writes multiple data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval None + */ +void IOE_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + I2Cx_WriteMultiple(Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief IOE delay + * @param Delay: Delay in ms + * @retval None + */ +void IOE_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} +#endif /* USE_IOEXPANDER */ + +/********************************* LINK MFX ***********************************/ + +#if defined(USE_IOEXPANDER) +/** + * @brief Initializes MFX low level. + * @retval None + */ +void MFX_IO_Init(void) +{ + I2Cx_Init(); +} + +/** + * @brief DeInitializes MFX low level. + * @retval None + */ +void MFX_IO_DeInit(void) +{ +} + +/** + * @brief Configures MFX low level interrupt. + * @retval None + */ +void MFX_IO_ITConfig(void) +{ + static uint8_t mfx_io_it_enabled = 0; + GPIO_InitTypeDef gpio_init_structure; + + if(mfx_io_it_enabled == 0) + { + mfx_io_it_enabled = 1; + /* Enable the GPIO EXTI clock */ + __HAL_RCC_GPIOI_CLK_ENABLE(); + __HAL_RCC_SYSCFG_CLK_ENABLE(); + + gpio_init_structure.Pin = GPIO_PIN_8; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_LOW; + gpio_init_structure.Mode = GPIO_MODE_IT_RISING; + HAL_GPIO_Init(GPIOI, &gpio_init_structure); + + /* Enable and set GPIO EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(EXTI9_5_IRQn), 0x0F, 0x0F); + HAL_NVIC_EnableIRQ((IRQn_Type)(EXTI9_5_IRQn)); + } +} + +/** + * @brief MFX writes single data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Value: Data to be written + * @retval None + */ +void MFX_IO_Write(uint16_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_Write((uint8_t) Addr, Reg, Value); +} + +/** + * @brief MFX reads single data. + * @param Addr: I2C address + * @param Reg: Register address + * @retval Read data + */ +uint8_t MFX_IO_Read(uint16_t Addr, uint8_t Reg) +{ + return I2Cx_Read((uint8_t) Addr, Reg); +} + +/** + * @brief MFX reads multiple data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval Number of read data + */ +uint16_t MFX_IO_ReadMultiple(uint16_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + return I2Cx_ReadMultiple((uint8_t)Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief MFX delay + * @param Delay: Delay in ms + * @retval None + */ +void MFX_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/** + * @brief Used by Lx family but requested for MFX component compatibility. + * @retval None + */ +void MFX_IO_Wakeup(void) +{ +} + +/** + * @brief Used by Lx family but requested for MXF component compatibility. + * @retval None + */ +void MFX_IO_EnableWakeupPin(void) +{ +} + +#endif /* USE_IOEXPANDER */ + +/********************************* LINK AUDIO *********************************/ + +/** + * @brief Initializes Audio low level. + * @retval None + */ +void AUDIO_IO_Init(void) +{ + I2Cx_Init(); +} + +/** + * @brief Deinitializes Audio low level. + * @retval None + */ +void AUDIO_IO_DeInit(void) +{ +} + +/** + * @brief Writes a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @param Value: Data to be written + * @retval None + */ +void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value) +{ + uint16_t tmp = Value; + + Value = ((uint16_t)(tmp >> 8) & 0x00FF); + + Value |= ((uint16_t)(tmp << 8)& 0xFF00); + + I2Cx_WriteMultiple(Addr, Reg, I2C_MEMADD_SIZE_16BIT,(uint8_t*)&Value, 2); +} + +/** + * @brief Reads a single data. + * @param Addr: I2C address + * @param Reg: Reg address + * @retval Data to be read + */ +uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg) +{ + uint16_t read_value = 0, tmp = 0; + + I2Cx_ReadMultiple(Addr, Reg, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&read_value, 2); + + tmp = ((uint16_t)(read_value >> 8) & 0x00FF); + + tmp |= ((uint16_t)(read_value << 8)& 0xFF00); + + read_value = tmp; + + return read_value; +} + +/** + * @brief AUDIO Codec delay + * @param Delay: Delay in ms + * @retval None + */ +void AUDIO_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/********************************* LINK CAMERA ********************************/ + +/** + * @brief Initializes Camera low level. + * @retval None + */ +void CAMERA_IO_Init(void) +{ + I2Cx_Init(); +} + +/** + * @brief Camera writes single data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Value: Data to be written + * @retval None + */ +void CAMERA_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value) +{ + uint16_t tmp = Value; + + if(Addr == CAMERA_I2C_ADDRESS_2) + { + I2Cx_WriteMultiple(Addr, Reg, I2C_MEMADD_SIZE_16BIT,(uint8_t*)&Value, 1); + } + else + { + /* For S5K5CAG sensor, 16 bits accesses are used */ + Value = ((uint16_t)(tmp >> 8) & 0x00FF); + Value |= ((uint16_t)(tmp << 8)& 0xFF00); + I2Cx_WriteMultiple(Addr, Reg, I2C_MEMADD_SIZE_16BIT,(uint8_t*)&Value, 2); + } +} + +/** + * @brief Camera reads single data. + * @param Addr: I2C address + * @param Reg: Register address + * @retval Read data + */ +uint16_t CAMERA_IO_Read(uint8_t Addr, uint16_t Reg) +{ + uint16_t read_value = 0, tmp = 0; + + if(Addr == CAMERA_I2C_ADDRESS_2) + { + I2Cx_ReadMultiple(Addr , Reg, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&read_value, 1); + } + else + { + /* For S5K5CAG sensor, 16 bits accesses are used */ + I2Cx_ReadMultiple(Addr, Reg, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&read_value, 2); + tmp = ((uint16_t)(read_value >> 8) & 0x00FF); + tmp |= ((uint16_t)(read_value << 8)& 0xFF00); + read_value = tmp; + } + + return read_value; +} + +/** + * @brief Camera delay + * @param Delay: Delay in ms + * @retval None + */ +void CAMERA_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/******************************** LINK I2C EEPROM *****************************/ + +/** + * @brief Initializes peripherals used by the I2C EEPROM driver. + * @retval None + */ +void EEPROM_IO_Init(void) +{ + I2Cx_Init(); +} + +/** + * @brief Write data to I2C EEPROM driver in using DMA channel. + * @param DevAddress: Target device address + * @param MemAddress: Internal memory address + * @param pBuffer: Pointer to data buffer + * @param BufferSize: Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize) +{ + return (I2Cx_WriteMultiple(DevAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, pBuffer, BufferSize)); +} + +/** + * @brief Read data from I2C EEPROM driver in using DMA channel. + * @param DevAddress: Target device address + * @param MemAddress: Internal memory address + * @param pBuffer: Pointer to data buffer + * @param BufferSize: Amount of data to be read + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize) +{ + return (I2Cx_ReadMultiple(DevAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, pBuffer, BufferSize)); +} + +/** + * @brief Checks if target device is ready for communication. + * @note This function is used with Memory devices + * @param DevAddress: Target device address + * @param Trials: Number of trials + * @retval HAL status + */ +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials) +{ + return (I2Cx_IsDeviceReady(DevAddress, Trials)); +} + +/******************************** LINK TS (TouchScreen) *****************************/ + +/** + * @brief Initialize I2C communication + * channel from MCU to TouchScreen (TS). + */ +void TS_IO_Init(void) +{ + I2Cx_Init(); +} + +/** + * @brief Writes single data with I2C communication + * channel from MCU to TouchScreen. + * @param Addr: I2C address + * @param Reg: Register address + * @param Value: Data to be written + */ +void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_Write(Addr, Reg, Value); +} + +/** + * @brief Reads single data with I2C communication + * channel from TouchScreen. + * @param Addr: I2C address + * @param Reg: Register address + * @retval Read data + */ +uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg) +{ + return I2Cx_Read(Addr, Reg); +} + +/** + * @brief Reads multiple data with I2C communication + * channel from TouchScreen. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval Number of read data + */ +uint16_t TS_IO_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + return I2Cx_ReadMultiple(Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief Writes multiple data with I2C communication + * channel from MCU to TouchScreen. + * @param Addr: I2C address + * @param Reg: Register address + * @param Buffer: Pointer to data buffer + * @param Length: Length of the data + * @retval None + */ +void TS_IO_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length) +{ + I2Cx_WriteMultiple(Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length); +} + +/** + * @brief Delay function used in TouchScreen low level driver. + * @param Delay: Delay in ms + * @retval None + */ +void TS_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +/**************************** LINK OTM8009A (Display driver) ******************/ +/** + * @brief OTM8009A delay + * @param Delay: Delay in ms + */ +void OTM8009A_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} + +#if defined(USE_LCD_HDMI) +/**************************** LINK ADV7533 DSI-HDMI (Display driver) **********/ +/** + * @brief Initializes HDMI IO low level. + * @retval None + */ +void HDMI_IO_Init(void) +{ + I2Cx_Init(); +} + +/** + * @brief HDMI writes single data. + * @param Addr: I2C address + * @param Reg: Register address + * @param Value: Data to be written + * @retval None + */ +void HDMI_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value) +{ + I2Cx_Write(Addr, Reg, Value); +} + +/** + * @brief Reads single data with I2C communication + * channel from HDMI bridge. + * @param Addr: I2C address + * @param Reg: Register address + * @retval Read data + */ +uint8_t HDMI_IO_Read(uint8_t Addr, uint8_t Reg) +{ + return I2Cx_Read(Addr, Reg); +} + +/** + * @brief HDMI delay + * @param Delay: Delay in ms + * @retval None + */ +void HDMI_IO_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} +#endif /* USE_LCD_HDMI */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval.h new file mode 100644 index 00000000..9028445f --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval.h @@ -0,0 +1,436 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval.h + * @author MCD Application Team + * @brief This file contains definitions for STM32F769I_EVAL LEDs, + * push-buttons and COM ports hardware resources. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_EVAL_H +#define __STM32F769I_EVAL_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @addtogroup STM32F769I_EVAL_LOW_LEVEL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_LOW_LEVEL_Exported_Types LOW LEVEL Exported Types + * @{ + */ +typedef enum +{ +LED1 = 0, +LED_GREEN = LED1, +LED2 = 1, +LED_ORANGE = LED2, +LED3 = 2, +LED_RED = LED3, +LED4 = 3, +LED_BLUE = LED4 +}Led_TypeDef; + +typedef enum +{ + BUTTON_WAKEUP = 0, + BUTTON_TAMPER = 1, + BUTTON_KEY = 2 +}Button_TypeDef; + +typedef enum +{ + BUTTON_MODE_GPIO = 0, + BUTTON_MODE_EXTI = 1 +}ButtonMode_TypeDef; + +#if defined(USE_IOEXPANDER) +typedef enum +{ + JOY_MODE_GPIO = 0, + JOY_MODE_EXTI = 1 +}JOYMode_TypeDef; + +typedef enum +{ + JOY_NONE = 0, + JOY_SEL = 1, + JOY_DOWN = 2, + JOY_LEFT = 3, + JOY_RIGHT = 4, + JOY_UP = 5 +}JOYState_TypeDef; +#endif /* USE_IOEXPANDER */ + +typedef enum +{ + COM1 = 0, + COM2 = 1 +}COM_TypeDef; +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LOW_LEVEL_Exported_Constants LOW LEVEL Exported Constants + * @{ + */ + +/** + * @brief Define for STM32F769I_EVAL board + */ +#if !defined (USE_STM32F769I_EVAL) + #define USE_STM32F769I_EVAL +#endif + +/** @addtogroup STM32F769I_EVAL_LOW_LEVEL_LED EVAL LOW LEVEL LED + * @{ + */ +#define LEDn ((uint32_t)4) + +#define LED1_GPIO_PORT GPIOI +#define LED1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define LED1_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define LED1_PIN GPIO_PIN_15 + +#define LED2_GPIO_PORT GPIOJ +#define LED2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOJ_CLK_ENABLE() +#define LED2_GPIO_CLK_DISABLE() __HAL_RCC_GPIOJ_CLK_DISABLE() +#define LED2_PIN GPIO_PIN_0 + +#define LED3_GPIO_PORT GPIOJ +#define LED3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOJ_CLK_ENABLE() +#define LED3_GPIO_CLK_DISABLE() __HAL_RCC_GPIOJ_CLK_DISABLE() +#define LED3_PIN GPIO_PIN_1 + +#define LED4_GPIO_PORT GPIOJ +#define LED4_GPIO_CLK_ENABLE() __HAL_RCC_GPIOJ_CLK_ENABLE() +#define LED4_GPIO_CLK_DISABLE() __HAL_RCC_GPIOJ_CLK_DISABLE() +#define LED4_PIN GPIO_PIN_3 + +#define LEDx_GPIO_CLK_ENABLE(__INDEX__) do{if((__INDEX__) == 0) LED1_GPIO_CLK_ENABLE(); else \ + if((__INDEX__) == 1) LED2_GPIO_CLK_ENABLE(); else \ + if((__INDEX__) == 2) LED3_GPIO_CLK_ENABLE(); else \ + if((__INDEX__) == 3) LED4_GPIO_CLK_ENABLE(); \ + }while(0) + +#define LEDx_GPIO_CLK_DISABLE(__INDEX__) do{if((__INDEX__) == 0) LED1_GPIO_CLK_DISABLE(); else \ + if((__INDEX__) == 1) LED2_GPIO_CLK_DISABLE(); else \ + if((__INDEX__) == 2) LED3_GPIO_CLK_DISABLE(); else \ + if((__INDEX__) == 3) LED4_GPIO_CLK_DISABLE(); \ + }while(0) + +/** + * @} + */ + +/** + * @brief MFX_IRQOUt pin + */ +#define MFX_IRQOUT_PIN GPIO_PIN_8 +#define MFX_IRQOUT_GPIO_PORT GPIOI +#define MFX_IRQOUT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() +#define MFX_IRQOUT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE() +#define MFX_IRQOUT_EXTI_IRQn EXTI9_5_IRQn + +/** @addtogroup STM32F769I_EVAL_LOW_LEVEL_BUTTON LOW LEVEL BUTTON + * @{ + */ +/* Joystick pins are connected to IO Expander (accessible through I2C1 interface) */ +#define BUTTONn ((uint8_t)3) + +/** + * @brief Wakeup push-button + */ +#define WAKEUP_BUTTON_PIN GPIO_PIN_13 +#define WAKEUP_BUTTON_GPIO_PORT GPIOC +#define WAKEUP_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define WAKEUP_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE() +#define WAKEUP_BUTTON_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief Tamper push-button + */ +#define TAMPER_BUTTON_PIN GPIO_PIN_13 +#define TAMPER_BUTTON_GPIO_PORT GPIOC +#define TAMPER_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define TAMPER_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE() +#define TAMPER_BUTTON_EXTI_IRQn EXTI15_10_IRQn + +/** + * @brief Key push-button + */ +#define KEY_BUTTON_PIN GPIO_PIN_13 +#define KEY_BUTTON_GPIO_PORT GPIOC +#define KEY_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define KEY_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE() +#define KEY_BUTTON_EXTI_IRQn EXTI15_10_IRQn + +#define BUTTONx_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == 0) WAKEUP_BUTTON_GPIO_CLK_ENABLE(); else\ + if((__INDEX__) == 1) TAMPER_BUTTON_GPIO_CLK_ENABLE(); else\ + KEY_BUTTON_GPIO_CLK_ENABLE(); } while(0) + +#define BUTTONx_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? WAKEUP_BUTTON_GPIO_CLK_DISABLE() :\ + ((__INDEX__) == 1) ? TAMPER_BUTTON_GPIO_CLK_DISABLE() : KEY_BUTTON_GPIO_CLK_DISABLE()) +/** + * @} + */ + +/** @addtogroup STM32F769I_EVAL_LOW_LEVEL_COM LOW LEVEL COM + * @{ + */ +#define COMn ((uint8_t)1) + +/** + * @brief Definition for COM port1, connected to USART1 + */ +#define EVAL_COM1 USART1 +#define EVAL_COM1_CLK_ENABLE() __HAL_RCC_USART1_CLK_ENABLE() +#define EVAL_COM1_CLK_DISABLE() __HAL_RCC_USART1_CLK_DISABLE() + +#define EVAL_COM1_TX_PIN GPIO_PIN_9 +#define EVAL_COM1_TX_GPIO_PORT GPIOA +#define EVAL_COM1_TX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define EVAL_COM1_TX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define EVAL_COM1_TX_AF GPIO_AF7_USART1 + +#define EVAL_COM1_RX_PIN GPIO_PIN_10 +#define EVAL_COM1_RX_GPIO_PORT GPIOA +#define EVAL_COM1_RX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define EVAL_COM1_RX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define EVAL_COM1_RX_AF GPIO_AF7_USART1 + +#define EVAL_COM1_IRQn USART1_IRQn + +#define EVAL_COMx_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) EVAL_COM1_CLK_ENABLE(); } while(0) +#define EVAL_COMx_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? EVAL_COM1_CLK_DISABLE() : 0) + +#define EVAL_COMx_TX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) EVAL_COM1_TX_GPIO_CLK_ENABLE(); } while(0) +#define EVAL_COMx_TX_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? EVAL_COM1_TX_GPIO_CLK_DISABLE() : 0) + +#define EVAL_COMx_RX_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == COM1) EVAL_COM1_RX_GPIO_CLK_ENABLE(); } while(0) +#define EVAL_COMx_RX_GPIO_CLK_DISABLE(__INDEX__) (((__INDEX__) == 0) ? EVAL_COM1_RX_GPIO_CLK_DISABLE() : 0) + +/** + * @brief Definition for Potentiometer, connected to ADC3 + */ +#define ADCx ADC3 +#define ADCx_CLK_ENABLE() __HAL_RCC_ADC3_CLK_ENABLE() +#define ADCx_CHANNEL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() + +#define ADCx_FORCE_RESET() __HAL_RCC_ADC_FORCE_RESET() +#define ADCx_RELEASE_RESET() __HAL_RCC_ADC_RELEASE_RESET() + +/* Definition for ADCx Channel Pin */ +#define ADCx_CHANNEL_PIN GPIO_PIN_10 +#define ADCx_CHANNEL_GPIO_PORT GPIOF + +/* Definition for ADCx's Channel */ +#define ADCx_CHANNEL ADC_CHANNEL_8 +#define SAMPLINGTIME ADC_SAMPLETIME_3CYCLES +#define ADCx_POLL_TIMEOUT 10 + +/** + * @brief Joystick Pins definition + */ +#if defined(USE_IOEXPANDER) +#define JOY_SEL_PIN IO_PIN_0 +#define JOY_DOWN_PIN IO_PIN_1 +#define JOY_LEFT_PIN IO_PIN_2 +#define JOY_RIGHT_PIN IO_PIN_3 +#define JOY_UP_PIN IO_PIN_4 +#define JOY_NONE_PIN JOY_ALL_PINS +#define JOY_ALL_PINS (IO_PIN_0 | IO_PIN_1 | IO_PIN_2 | IO_PIN_3 | IO_PIN_4) +#endif /* USE_IOEXPANDER */ +/** + * @brief Eval Pins definition connected to MFX + */ + +#if defined(USE_IOEXPANDER) +#define XSDN_PIN IO_PIN_16 +#define MII_INT_PIN IO_PIN_13 +#define RSTI_PIN IO_PIN_11 +#define CAM_PLUG_PIN IO_PIN_12 +#define TS_INT_PIN IO_PIN_14 +#define AUDIO_INT_PIN IO_PIN_5 +#define OTG_FS1_OVER_CURRENT_PIN IO_PIN_6 +#define OTG_FS1_POWER_SWITCH_PIN IO_PIN_7 +#define OTG_FS2_OVER_CURRENT_PIN IO_PIN_8 +#define OTG_FS2_POWER_SWITCH_PIN IO_PIN_9 +#define SD1_DETECT_PIN IO_PIN_15 +#define SD2_DETECT_PIN IO_PIN_10 +#define SD_DETECT_PIN SD1_DETECT_PIN +#endif /* USE_IOEXPANDER */ + + +/* Exported constant IO ------------------------------------------------------*/ + +/* The MFX_I2C_ADDR input pin selects the MFX I2C device address + MFX_I2C_ADDR input pin MFX I2C device address + 0 b: 1000 010x (0x84) + 1 b: 1000 011x (0x86) + This input is sampled during the MFX firmware startup. */ +#define IO_I2C_ADDRESS ((uint16_t)0x84) /*mfx MFX_I2C_ADDR 0*/ +#define IO_I2C_ADDRESS_2 ((uint16_t)0x86) /*mfx MFX_I2C_ADDR 1*/ +/** + * @brief TouchScreen FT6206 Slave I2C address 1 + */ +#define TS_I2C_ADDRESS ((uint16_t)0x54) + +/** + * @brief TouchScreen FT6336G Slave I2C address 2 + */ +#define TS_I2C_ADDRESS_A02 ((uint16_t)0x70) + +/** + * @brief LCD DSI Slave I2C address 1 + */ +#define LCD_DSI_ADDRESS TS_I2C_ADDRESS + +/** + * @brief LCD DSI Slave I2C address 2 + */ +#define LCD_DSI_ADDRESS_A02 TS_I2C_ADDRESS_A02 + +#define CAMERA_I2C_ADDRESS ((uint16_t)0x5A) +#define CAMERA_I2C_ADDRESS_2 ((uint16_t)0x78) +#define AUDIO_I2C_ADDRESS ((uint16_t)0x34) +#define EEPROM_I2C_ADDRESS_A01 ((uint16_t)0xA0) +#define EEPROM_I2C_ADDRESS_A02 ((uint16_t)0xA6) +/* I2C clock speed configuration (in Hz) + WARNING: + Make sure that this define is not already declared in other files (ie. + stm32f769i_eval.h file). It can be used in parallel by other modules. */ +#ifndef I2C_SPEED + #define I2C_SPEED ((uint32_t)100000) +#endif /* I2C_SPEED */ + +/* User can use this section to tailor I2Cx/I2Cx instance used and associated + resources */ +/* Definition for I2Cx clock resources */ +#define EVAL_I2Cx I2C1 +#define EVAL_I2Cx_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE() +#define EVAL_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE() +#define EVAL_I2Cx_SCL_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() + +#define EVAL_I2Cx_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET() +#define EVAL_I2Cx_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET() + +/* Definition for I2Cx Pins */ +#define EVAL_I2Cx_SCL_PIN GPIO_PIN_8 +#define EVAL_I2Cx_SCL_SDA_GPIO_PORT GPIOB +#define EVAL_I2Cx_SCL_SDA_AF GPIO_AF4_I2C1 +#define EVAL_I2Cx_SDA_PIN GPIO_PIN_9 + +/* I2C interrupt requests */ +#define EVAL_I2Cx_EV_IRQn I2C1_EV_IRQn +#define EVAL_I2Cx_ER_IRQn I2C1_ER_IRQn + +/* I2C TIMING Register define when I2C clock source is SYSCLK */ +/* I2C TIMING is calculated from APB1 source clock = 50 MHz */ +/* Due to the big MOFSET capacity for adapting the camera level the rising time is very large (>1us) */ +/* 0x40912732 takes in account the big rising and aims a clock of 100khz */ +#ifndef EVAL_I2Cx_TIMING +#define EVAL_I2Cx_TIMING ((uint32_t)0x40912732) +#endif /* EVAL_I2Cx_TIMING */ + +/** + * @} + */ + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LOW_LEVEL_Exported_Macros LOW LEVEL Exported Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LOW_LEVEL_Exported_Functions LOW LEVEL Exported Functions + * @{ + */ +uint32_t BSP_GetVersion(void); +void BSP_LED_Init(Led_TypeDef Led); +void BSP_LED_DeInit(Led_TypeDef Led); +void BSP_LED_On(Led_TypeDef Led); +void BSP_LED_Off(Led_TypeDef Led); +void BSP_LED_Toggle(Led_TypeDef Led); +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef ButtonMode); +void BSP_PB_DeInit(Button_TypeDef Button); +uint32_t BSP_PB_GetState(Button_TypeDef Button); +void BSP_COM_Init(COM_TypeDef COM, UART_HandleTypeDef *husart); +void BSP_COM_DeInit(COM_TypeDef COM, UART_HandleTypeDef *huart); +void BSP_POTENTIOMETER_Init(void); +uint32_t BSP_POTENTIOMETER_GetLevel(void); +#if defined(USE_IOEXPANDER) +uint8_t BSP_JOY_Init(JOYMode_TypeDef JoyMode); +void BSP_JOY_DeInit(void); +JOYState_TypeDef BSP_JOY_GetState(void); +#endif /* USE_IOEXPANDER */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_EVAL_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_audio.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_audio.c new file mode 100644 index 00000000..e922093d --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_audio.c @@ -0,0 +1,1642 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_audio.c + * @author MCD Application Team + * @brief This file provides the Audio driver for the STM32F769I-EVAL + * evaluation board. + @verbatim + How To use this driver: + ----------------------- + + This driver supports STM32F7xx devices on STM32F769I-EVAL (MB1219) Evaluation boards. + + Call the function BSP_AUDIO_OUT_Init( + OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, + OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH) + Volume : Initial volume to be set (0 is min (mute), 100 is max (100%) + AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...) + this parameter is relative to the audio file/stream type. + ) + This function configures all the hardware required for the audio application (codec, I2C, SAI, + GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK. + If the returned value is different from AUDIO_OK or the function is stuck then the communication with + the codec or the MFX has failed (try to un-plug the power or reset device in this case). + - OUTPUT_DEVICE_SPEAKER : only speaker will be set as output for the audio stream. + - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream. + - OUTPUT_DEVICE_BOTH : both Speaker and Headphone are used as outputs for the audio stream + at the same time. + Note. On STM32F769I-EVAL SAI_DMA is configured in CIRCULAR mode. Due to this the application + does NOT need to call BSP_AUDIO_OUT_ChangeBuffer() to assure streaming. + + Call the function BSP_EVAL_AUDIO_OUT_Play( + pBuffer: pointer to the audio data file address + Size : size of the buffer to be sent in Bytes + ) + to start playing (for the first time) from the audio file/stream. + + Call the function BSP_AUDIO_OUT_Pause() to pause playing + + Call the function BSP_AUDIO_OUT_Resume() to resume playing. + Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called + for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case). + Note. This function should be called only when the audio file is played or paused (not stopped). + + For each mode, you may need to implement the relative callback functions into your code. + The Callback functions are named AUDIO_OUT_XXX_CallBack() and only their prototypes are declared in + the stm32f769i_eval_audio.h file. (refer to the example for more details on the callbacks implementations) + + To Stop playing, to modify the volume level, the frequency, the audio frame slot, + the device output mode the mute or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(), + AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetAudioFrameSlot(), BSP_AUDIO_OUT_SetOutputMode(), + BSP_AUDIO_OUT_SetMute() and BSP_AUDIO_OUT_Stop(). + + The driver API and the callback functions are at the end of the stm32f769i_eval_audio.h file. + + Driver architecture: + -------------------- + + This driver provides the High Audio Layer: consists of the function API exported in the stm32f769i_eval_audio.h file + (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...) + + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/ + providing the audio file/stream. These functions are also included as local functions into + the stm32f769i_eval_audio_codec.c file (DFSDMx_Init(), DFSDMx_DeInit(), SAIx_Init() and SAIx_DeInit()) + + Known Limitations: + ------------------ + 1- If the TDM Format used to play in parallel 2 audio Stream (the first Stream is configured in codec SLOT0 and second + Stream in SLOT1) the Pause/Resume, volume and mute feature will control the both streams. + 2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, + File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file. + 3- Supports only Stereo audio streaming. + 4- Supports only 16-bits audio data size. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f769i_eval.c +- stm32f7xx_hal_sai.c +- stm32f7xx_hal_dfsdm.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- wm8994.c +- adv7533.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval_audio.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_AUDIO STM32F769I_EVAL AUDIO + * @brief This file includes the low layer driver for wm8994 Audio Codec + * available on STM32F769I-EVAL evaluation board(MB1219). + * @{ + */ + +/** @defgroup STM32F769I_EVAL_AUDIO_Private_Types STM32F769I_EVAL_AUDIO Private Types + * @{ + */ +typedef struct +{ + uint16_t *pRecBuf; /* Pointer to record user buffer */ + uint32_t RecSize; /* Size to record in mono, double size to record in stereo */ +}AUDIOIN_TypeDef; + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_AUDIO_Private_Defines STM32F769I_EVAL_AUDIO Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_AUDIO_Private_Macros STM32F769I_EVAL_AUDIO Private Macros + * @{ + */ +/*### RECORD ###*/ +#define DFSDM_OVER_SAMPLING(__FREQUENCY__) \ + (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 256 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 256 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 128 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 128 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 64 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 64 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 40 : 20 \ + +#define DFSDM_CLOCK_DIVIDER(__FREQUENCY__) \ + (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 24 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 4 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 24 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 4 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 24 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 4 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 25 : 25 \ + +#define DFSDM_FILTER_ORDER(__FREQUENCY__) \ + (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? DFSDM_FILTER_SINC3_ORDER \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? DFSDM_FILTER_SINC3_ORDER \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? DFSDM_FILTER_SINC3_ORDER \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? DFSDM_FILTER_SINC3_ORDER \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? DFSDM_FILTER_SINC4_ORDER \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? DFSDM_FILTER_SINC3_ORDER \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? DFSDM_FILTER_SINC3_ORDER : DFSDM_FILTER_SINC5_ORDER \ + +#define DFSDM_RIGHT_BIT_SHIFT(__FREQUENCY__) \ + (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 8 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 8 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 3 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 4 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 7 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 0 \ + : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 0 : 4 \ + +/* Saturate the record PCM sample */ +#define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N))) +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_AUDIO_Private_Variables STM32F769I_EVAL_AUDIO Private Variables + * @{ + */ +/*### PLAY ###*/ +AUDIO_DrvTypeDef *audio_drv; +SAI_HandleTypeDef haudio_out_sai; + +/*### RECORD ###*/ +AUDIOIN_TypeDef hAudioIn; + +DFSDM_Channel_HandleTypeDef haudio_in_dfsdm_leftchannel; +DFSDM_Channel_HandleTypeDef haudio_in_dfsdm_rightchannel; +DFSDM_Filter_HandleTypeDef haudio_in_dfsdm_leftfilter; +DFSDM_Filter_HandleTypeDef haudio_in_dfsdm_rightfilter; +DMA_HandleTypeDef hdma_dfsdm_left; +DMA_HandleTypeDef hdma_dfsdm_right; + +/* Buffers for right and left samples */ +int32_t *pScratchBuff[DEFAULT_AUDIO_IN_CHANNEL_NBR]; +int32_t ScratchSize; + +/* Output device to be used: headphone by default */ +static uint16_t AudioOut_Device = OUTPUT_DEVICE_HEADPHONE1; + +/* Buffers status flags */ +uint32_t DmaLeftRecHalfBuffCplt = 0; +uint32_t DmaLeftRecBuffCplt = 0; +uint32_t DmaRightRecHalfBuffCplt = 0; +uint32_t DmaRightRecBuffCplt = 0; + +/* Application Buffer Trigger */ +__IO uint32_t AppBuffTrigger = 0; +__IO uint32_t AppBuffHalf = 0; + +#if defined(USE_LCD_HDMI) +AUDIO_DrvTypeDef *hdmi_drv; +/* Audio device ID */ +static uint32_t DeviceId = 0x00; +#endif /* USE_LCD_HDMI */ + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_AUDIO_Private_Function_Prototypes STM32F769I_EVAL_AUDIO Private Function Prototypes + * @{ + */ +static void SAIx_Init(uint32_t AudioFreq); +static void SAIx_DeInit(void); +static void DFSDMx_ChannelMspInit(void); +static void DFSDMx_FilterMspInit(void); +static void DFSDMx_ChannelMspDeInit(void); +static void DFSDMx_FilterMspDeInit(void); +static uint8_t DFSDMx_Init(uint32_t AudioFreq); +static uint8_t DFSDMx_DeInit(void); +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_AUDIO_OUT_Private_Functions STM32F769I_EVAL_AUDIO_OUT Private Functions + * @{ + */ + +/** + * @brief Configure the audio peripherals. + * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, + * or OUTPUT_DEVICE_BOTH. + * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) + * @param AudioFreq: Audio frequency used to play the audio stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq) +{ + uint8_t ret = AUDIO_ERROR; + AudioOut_Device = OutputDevice; + + /* Disable SAI */ + SAIx_DeInit(); + + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* SAI data transfer preparation: + Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ + haudio_out_sai.Instance = AUDIO_SAIx; + if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) + { + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); + } + SAIx_Init(AudioFreq); + +#if defined(USE_LCD_HDMI) + if((OutputDevice & OUTPUT_DEVICE_HDMI) == OUTPUT_DEVICE_HDMI) + { + /* adv7533 audio driver initialization */ + DeviceId = adv7533_drv.ReadID(ADV7533_CEC_DSI_I2C_ADDR); + + if(DeviceId == ADV7533_ID) + { + /* Initialize the audio driver structure */ + hdmi_drv = &adv7533_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + hdmi_drv->Init(ADV7533_MAIN_I2C_ADDR, OutputDevice, Volume, AudioFreq); + } + } +#endif /* USE_LCD_HDMI */ + + if((((OutputDevice & OUTPUT_DEVICE_BOTH) > 0) && + ((OutputDevice & OUTPUT_DEVICE_BOTH) <= OUTPUT_DEVICE_BOTH)) || + ((OutputDevice & OUTPUT_DEVICE_AUTO) == OUTPUT_DEVICE_AUTO)) + { + /* wm8994 codec initialization */ + if((wm8994_drv.ReadID(AUDIO_I2C_ADDRESS)) == WM8994_ID) + { + /* Reset the Codec Registers */ + wm8994_drv.Reset(AUDIO_I2C_ADDRESS); + /* Initialize the audio driver structure */ + audio_drv = &wm8994_drv; + ret = AUDIO_OK; + } + else + { + ret = AUDIO_ERROR; + } + + if(ret == AUDIO_OK) + { + /* Initialize the codec internal registers */ + audio_drv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq); + } + } + + return ret; +} + +/** + * @brief Start playing audio stream from a data buffer for a determined size. + * @param pBuffer: Pointer to the buffer + * @param Size: Number of audio data BYTES. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size) +{ + uint8_t ret = 0; +#if defined(USE_LCD_HDMI) + /* ADV7533 used */ + if((AudioOut_Device & OUTPUT_DEVICE_HDMI) == OUTPUT_DEVICE_HDMI) + { + if(DeviceId == ADV7533_ID) + { + /* Call the audio Codec Play function */ + if(hdmi_drv->Play(ADV7533_MAIN_I2C_ADDR, (uint16_t *)pBuffer, Size) != 0) + { + ret = AUDIO_ERROR; + } + } + } +#endif /* USE_LCD_HDMI */ + + /* WM8994 used */ + if((((AudioOut_Device & OUTPUT_DEVICE_BOTH) > 0) && + ((AudioOut_Device & OUTPUT_DEVICE_BOTH) <= OUTPUT_DEVICE_BOTH)) || + ((AudioOut_Device & OUTPUT_DEVICE_AUTO) == OUTPUT_DEVICE_AUTO)) + { + /* Call the audio Codec Play function */ + if(audio_drv->Play(AUDIO_I2C_ADDRESS, (uint16_t *)pBuffer, Size) != 0) + { + ret = AUDIO_ERROR; + } + } + + if(ret == AUDIO_ERROR) + { + return AUDIO_ERROR; + } + else + { + /* Update the Media layer and enable it for play */ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, DMA_MAX(Size / AUDIODATA_SIZE)); + + return AUDIO_OK; + } +} + +/** + * @brief Send n-Bytes on the SAI interface. + * @param pData: pointer on data address + * @param Size: number of data to be written + * @retval None + */ +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size) +{ + HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pData, Size); +} + +/** + * @brief Pause the audio file stream. In case + * of using DMA, the DMA Pause feature is used. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Pause(void) +{ + uint8_t ret = 0; +#if defined(USE_LCD_HDMI) + /* ADV7533 used */ + if((AudioOut_Device & OUTPUT_DEVICE_HDMI) == OUTPUT_DEVICE_HDMI) + { + if(DeviceId == ADV7533_ID) + { + /* Call the audio Codec Pause function */ + if(hdmi_drv->Pause(ADV7533_MAIN_I2C_ADDR) != 0) + { + ret = AUDIO_ERROR; + } + } + } +#endif /* USE_LCD_HDMI */ + + /* WM8994 used */ + if((((AudioOut_Device & OUTPUT_DEVICE_BOTH) > 0) && + ((AudioOut_Device & OUTPUT_DEVICE_BOTH) <= OUTPUT_DEVICE_BOTH)) || + ((AudioOut_Device & OUTPUT_DEVICE_AUTO) == OUTPUT_DEVICE_AUTO)) + { + /* Call the audio Codec Pause function */ + if(audio_drv->Pause(AUDIO_I2C_ADDRESS) != 0) + { + ret = AUDIO_ERROR; + } + } + + if(ret == AUDIO_ERROR) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause function */ + HAL_SAI_DMAPause(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Resume the audio file stream. + * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only + * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() + * function for resume could lead to unexpected behaviour). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Resume(void) +{ + uint8_t ret = 0; +#if defined(USE_LCD_HDMI) + /* ADV7533 used */ + if((AudioOut_Device & OUTPUT_DEVICE_HDMI) == OUTPUT_DEVICE_HDMI) + { + if(DeviceId == ADV7533_ID) + { + /* Call the audio Codec Resume function */ + if(hdmi_drv->Resume(ADV7533_MAIN_I2C_ADDR) != 0) + { + ret = AUDIO_ERROR; + } + } + } +#endif /* USE_LCD_HDMI */ + + /* WM8994 used */ + if((((AudioOut_Device & OUTPUT_DEVICE_BOTH) > 0) && + ((AudioOut_Device & OUTPUT_DEVICE_BOTH) <= OUTPUT_DEVICE_BOTH)) || + ((AudioOut_Device & OUTPUT_DEVICE_AUTO) == OUTPUT_DEVICE_AUTO)) + { + /* Call the audio Codec Resume function */ + if(audio_drv->Resume(AUDIO_I2C_ADDRESS) != 0) + { + ret = AUDIO_ERROR; + } + } + + if(ret == AUDIO_ERROR) + { + return AUDIO_ERROR; + } + else + { + /* Call the Media layer pause/resume function */ + HAL_SAI_DMAResume(&haudio_out_sai); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Stop audio playing and Power down the Audio Codec. + * @param Option: could be one of the following parameters + * - CODEC_PDWN_SW: for software power off (by writing registers). + * Then no need to reconfigure the Codec after power on. + * - CODEC_PDWN_HW: completely shut down the codec (physically). + * Then need to reconfigure the Codec after power on. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option) +{ + uint8_t ret = 0; + + /* Call the Media layer stop function */ + HAL_SAI_DMAStop(&haudio_out_sai); + +#if defined(USE_LCD_HDMI) + /* ADV7533 used */ + if((AudioOut_Device & OUTPUT_DEVICE_HDMI) == OUTPUT_DEVICE_HDMI) + { + if(DeviceId == ADV7533_ID) + { + /* Call the audio Codec Stop function */ + if(hdmi_drv->Stop(ADV7533_MAIN_I2C_ADDR, Option) != 0) + { + ret = AUDIO_ERROR; + } + } + } +#endif /* USE_LCD_HDMI */ + + /* WM8994 used */ + if((((AudioOut_Device & OUTPUT_DEVICE_BOTH) > 0) && + ((AudioOut_Device & OUTPUT_DEVICE_BOTH) <= OUTPUT_DEVICE_BOTH)) || + ((AudioOut_Device & OUTPUT_DEVICE_AUTO) == OUTPUT_DEVICE_AUTO)) + { + /* Call the audio Codec Stop function */ + if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) + { + ret = AUDIO_ERROR; + } + } + + if(ret == AUDIO_ERROR) + { + return AUDIO_ERROR; + } + else + { + if(Option == CODEC_PDWN_HW) + { + /* Wait at least 100us */ + HAL_Delay(1); + } + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Control the current audio volume level. + * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for + * Mute and 100 for Max volume level). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume) +{ + /* Call the codec volume control function with converted volume value */ + if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Enable or disable the MUTE mode by software + * @param Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to + * unmute the codec and restore previous volume level. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd) +{ + uint8_t ret = 0; +#if defined(USE_LCD_HDMI) + /* ADV7533 used */ + if((AudioOut_Device & OUTPUT_DEVICE_HDMI) == OUTPUT_DEVICE_HDMI) + { + if(DeviceId == ADV7533_ID) + { + /* Call the audio Codec SetMute function */ + if(hdmi_drv->SetMute(ADV7533_MAIN_I2C_ADDR, Cmd) != 0) + { + ret = AUDIO_ERROR; + } + } + } +#endif /* USE_LCD_HDMI */ + + /* WM8994 used */ + if((((AudioOut_Device & OUTPUT_DEVICE_BOTH) > 0) && + ((AudioOut_Device & OUTPUT_DEVICE_BOTH) <= OUTPUT_DEVICE_BOTH)) || + ((AudioOut_Device & OUTPUT_DEVICE_AUTO) == OUTPUT_DEVICE_AUTO)) + { + /* Call the audio Codec SetMute function */ + if(audio_drv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0) + { + ret = AUDIO_ERROR; + } + } + + if(ret == AUDIO_ERROR) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Switch dynamically (while audio file is played) the output target + * (speaker or headphone). + * @param Output: The audio output target: OUTPUT_DEVICE_SPEAKER, + * OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output) +{ + /* Call the Codec output device function */ + if(audio_drv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0) + { + return AUDIO_ERROR; + } + else + { + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; + } +} + +/** + * @brief Update the audio frequency. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frequency. + * @retval None + */ +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq) +{ + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frequency configuration */ + haudio_out_sai.Init.AudioFrequency = AudioFreq; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Update the Audio frame slot configuration. + * @param AudioFrameSlot: specifies the audio Frame slot + * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the + * audio frame slot. + * @retval None + */ +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot) +{ + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Update the SAI audio frame slot configuration */ + haudio_out_sai.SlotInit.SlotActive = AudioFrameSlot; + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + + +/** + * @brief De-initialize the audio peripherals. + * @retval None + */ +void BSP_AUDIO_OUT_DeInit(void) +{ + SAIx_DeInit(); + /* DeInit the SAI MSP : this __weak function can be rewritten by the application */ + BSP_AUDIO_OUT_MspDeInit(&haudio_out_sai, NULL); +} + +/** + * @brief Tx Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f769i_eval_audio.h) */ + BSP_AUDIO_OUT_TransferComplete_CallBack(); +} + +/** + * @brief Tx Half Transfer completed callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai) +{ + /* Manage the remaining file size and new address offset: This function + should be coded by user (its prototype is already declared in stm32f769i_eval_audio.h) */ + BSP_AUDIO_OUT_HalfTransfer_CallBack(); +} + +/** + * @brief SAI error callbacks. + * @param hsai: SAI handle + * @retval None + */ +void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai) +{ + BSP_AUDIO_OUT_Error_CallBack(); +} + +/** + * @brief Manages the DMA full Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void) +{ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void) +{ +} + +/** + * @brief Manages the DMA FIFO error event. + * @retval None + */ +__weak void BSP_AUDIO_OUT_Error_CallBack(void) +{ +} + +/** + * @brief Initialize BSP_AUDIO_OUT MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params) +{ + static DMA_HandleTypeDef hdma_sai_tx; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable SAI clock */ + AUDIO_SAIx_CLK_ENABLE(); + + /* Enable GPIO clock */ + AUDIO_SAIx_MCLK_ENABLE(); + AUDIO_SAIx_SCK_SD_ENABLE(); + AUDIO_SAIx_FS_ENABLE(); + /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/ + gpio_init_structure.Pin = AUDIO_SAIx_FS_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = AUDIO_SAIx_FS_SD_MCLK_AF; + HAL_GPIO_Init(AUDIO_SAIx_FS_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_SAIx_SCK_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = AUDIO_SAIx_SCK_AF; + HAL_GPIO_Init(AUDIO_SAIx_SCK_SD_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_SAIx_SD_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = AUDIO_SAIx_FS_SD_MCLK_AF; + HAL_GPIO_Init(AUDIO_SAIx_SCK_SD_GPIO_PORT, &gpio_init_structure); + + gpio_init_structure.Pin = AUDIO_SAIx_MCLK_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = AUDIO_SAIx_FS_SD_MCLK_AF; + HAL_GPIO_Init(AUDIO_SAIx_MCLK_GPIO_PORT, &gpio_init_structure); + + /* Enable the DMA clock */ + AUDIO_SAIx_DMAx_CLK_ENABLE(); + + if(hsai->Instance == AUDIO_SAIx) + { + /* Configure the hdma_saiTx handle parameters */ + hdma_sai_tx.Init.Channel = AUDIO_SAIx_DMAx_CHANNEL; + hdma_sai_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_sai_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_sai_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_sai_tx.Init.PeriphDataAlignment = AUDIO_SAIx_DMAx_PERIPH_DATA_SIZE; + hdma_sai_tx.Init.MemDataAlignment = AUDIO_SAIx_DMAx_MEM_DATA_SIZE; + hdma_sai_tx.Init.Mode = DMA_CIRCULAR; + hdma_sai_tx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_sai_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + hdma_sai_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_sai_tx.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_sai_tx.Init.PeriphBurst = DMA_PBURST_SINGLE; + + hdma_sai_tx.Instance = AUDIO_SAIx_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsai, hdmatx, hdma_sai_tx); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&hdma_sai_tx); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&hdma_sai_tx); + } + + /* SAI DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_SAIx_DMAx_IRQ); +} + +/** + * @brief Deinitialize SAI MSP. + * @param hsai: SAI handle + * @param Params + * @retval None + */ +__weak void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* SAI DMA IRQ Channel deactivation */ + HAL_NVIC_DisableIRQ(AUDIO_SAIx_DMAx_IRQ); + + if(hsai->Instance == AUDIO_SAIx) + { + /* Deinitialize the DMA stream */ + HAL_DMA_DeInit(hsai->hdmatx); + } + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(hsai); + + /* Deactivates CODEC_SAI pins FS, SCK, MCK and SD by putting them in input mode */ + gpio_init_structure.Pin = AUDIO_SAIx_FS_PIN; + HAL_GPIO_DeInit(AUDIO_SAIx_FS_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_SAIx_SCK_PIN; + HAL_GPIO_DeInit(AUDIO_SAIx_SCK_SD_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_SAIx_SD_PIN; + HAL_GPIO_DeInit(AUDIO_SAIx_SCK_SD_GPIO_PORT, gpio_init_structure.Pin); + + gpio_init_structure.Pin = AUDIO_SAIx_MCLK_PIN; + HAL_GPIO_DeInit(AUDIO_SAIx_MCLK_GPIO_PORT, gpio_init_structure.Pin); + + /* Disable SAI clock */ + AUDIO_SAIx_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the applic + by surcharging this __weak function */ +} + +/** + * @brief Clock Config. + * @param hsai: might be required to set audio peripheral predivider if any. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @param Params + * @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params) +{ + RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; + + HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); + + /* Set the PLL configuration according to the audio frequency */ + if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) + { + /* Configure PLLSAI prescalers */ + /* PLLSAI_VCO: VCO_429M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 429/2 = 214.5 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 214.5/19 = 11.289 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 429; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 2; + rcc_ex_clk_init_struct.PLLI2SDivQ = 19; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + + } + else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_32K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */ + { + /* SAI clock config + PLLSAI_VCO: VCO_344M + SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 344/7 = 49.142 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 49.142/1 = 49.142 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 344; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 7; + rcc_ex_clk_init_struct.PLLI2SDivQ = 1; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + } +} + +/******************************************************************************* + Static Functions +*******************************************************************************/ + +/** + * @brief Initialize the Audio Codec audio interface (SAI). + * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. + * @note The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123 + * and user can update this configuration using + * @retval None + */ +static void SAIx_Init(uint32_t AudioFreq) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_SAIx; + + /* Disable SAI peripheral to allow access to SAI internal registers */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + /* Configure SAI_Block_x + LSBFirst: Disabled + DataSize: 16 */ + haudio_out_sai.Init.MonoStereoMode = SAI_STEREOMODE; + haudio_out_sai.Init.AudioFrequency = AudioFreq; + haudio_out_sai.Init.AudioMode = SAI_MODEMASTER_TX; + haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; + haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; + haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; + haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; + haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE; + haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; + haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE; + haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + haudio_out_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; + haudio_out_sai.Init.CompandingMode = SAI_NOCOMPANDING; + haudio_out_sai.Init.TriState = SAI_OUTPUT_NOTRELEASED; + haudio_out_sai.Init.Mckdiv = 0; + + /* Configure SAI_Block_x Frame + Frame Length: 64 + Frame active Length: 32 + FS Definition: Start frame + Channel Side identification + FS Polarity: FS active Low + FS Offset: FS asserted one bit before the first bit of slot 0 */ + haudio_out_sai.FrameInit.FrameLength = 64; + haudio_out_sai.FrameInit.ActiveFrameLength = 32; + haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; + haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; + haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; + + /* Configure SAI Block_x Slot + Slot First Bit Offset: 0 + Slot Size : 16 + Slot Number: 4 + Slot Active: All slot actives */ + haudio_out_sai.SlotInit.FirstBitOffset = 0; + haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + haudio_out_sai.SlotInit.SlotNumber = 4; + haudio_out_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_0123; + + HAL_SAI_Init(&haudio_out_sai); + + /* Enable SAI peripheral to generate MCLK */ + __HAL_SAI_ENABLE(&haudio_out_sai); +} + +/** + * @brief Deinitialize the Audio Codec audio interface (SAI). + * @retval None + */ +static void SAIx_DeInit(void) +{ + /* Initialize the haudio_out_sai Instance parameter */ + haudio_out_sai.Instance = AUDIO_SAIx; + + /* Disable SAI peripheral */ + __HAL_SAI_DISABLE(&haudio_out_sai); + + HAL_SAI_DeInit(&haudio_out_sai); +} + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_AUDIO_out_Private_Functions STM32F769I_EVAL_AUDIO_Out Private Functions + * @{ + */ + +/** + * @brief Initialize wave recording. + * @param AudioFreq: Audio frequency to be configured for the DFSDM peripheral. + * @param BitRes: Audio frequency to be configured for the DFSDM peripheral. + * @param ChnlNbr: Audio frequency to be configured for the DFSDM peripheral. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) +{ + + /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ + BSP_AUDIO_IN_ClockConfig(&haudio_in_dfsdm_leftfilter, AudioFreq, NULL); + + /* Init the SAI MSP: this __weak function can be redefined by the application*/ + BSP_AUDIO_IN_MspInit(); + + /* Initializes DFSDM peripheral */ + DFSDMx_Init(AudioFreq); + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Allocate channel buffer scratch + * @param pScratch : pointer to scratch tables. + * @param size of scratch buffer + */ +uint8_t BSP_AUDIO_IN_AllocScratch (int32_t *pScratch, uint32_t size) +{ + uint32_t idx; + + ScratchSize = size / DEFAULT_AUDIO_IN_CHANNEL_NBR; + + /* copy scratch pointers */ + for (idx = 0; idx < DEFAULT_AUDIO_IN_CHANNEL_NBR ; idx++) + { + pScratchBuff[idx] = (int32_t *)(pScratch + idx * ScratchSize); + } + /* Return AUDIO_OK */ + return AUDIO_OK; +} + +/** + * @brief Start audio recording. + * @param pbuf: Main buffer pointer for the recorded data storing + * @param size: Current size of the recorded buffer + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size) +{ + hAudioIn.pRecBuf = pbuf; + hAudioIn.RecSize = size; + /* Reset Application Buffer Trigger */ + AppBuffTrigger = 0; + AppBuffHalf = 0; + + /* Call the Media layer start function for right channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&haudio_in_dfsdm_rightfilter, pScratchBuff[0], ScratchSize)) + { + return AUDIO_ERROR; + } + + /* Call the Media layer start function for left channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&haudio_in_dfsdm_leftfilter, pScratchBuff[1], ScratchSize)) + { + return AUDIO_ERROR; + } + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Stop audio recording. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Stop(void) +{ + AppBuffTrigger = 0; + AppBuffHalf = 0; + + /* Call the Media layer stop function for right channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&haudio_in_dfsdm_rightfilter)) + { + return AUDIO_ERROR; + } + + /* Call the Media layer stop function for left channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&haudio_in_dfsdm_leftfilter)) + { + return AUDIO_ERROR; + } + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Pause the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Pause(void) +{ + /* Call the Media layer stop function */ + if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&haudio_in_dfsdm_rightfilter)) + { + return AUDIO_ERROR; + } + + /* Call the Media layer stop function */ + if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&haudio_in_dfsdm_leftfilter)) + { + return AUDIO_ERROR; + } + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Resume the audio file stream. + * @retval AUDIO_OK if correct communication, else wrong communication + */ +uint8_t BSP_AUDIO_IN_Resume(void) +{ + /* Call the Media layer start function for right channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&haudio_in_dfsdm_rightfilter, pScratchBuff[0], ScratchSize)) + { + return AUDIO_ERROR; + } + + /* Call the Media layer start function for left channel */ + if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&haudio_in_dfsdm_leftfilter, pScratchBuff[1], ScratchSize)) + { + return AUDIO_ERROR; + } + + /* Return AUDIO_OK when all operations are correctly done */ + return AUDIO_OK; +} + +/** + * @brief Deinit the audio IN peripherals. + * @retval None + */ +void BSP_AUDIO_IN_DeInit(void) +{ + BSP_AUDIO_IN_MspDeInit(); + DFSDMx_DeInit(); +} + + +/** + * @brief Regular conversion complete callback. + * @note In interrupt mode, user has to read conversion value in this function + using HAL_DFSDM_FilterGetRegularValue. + * @param hdfsdm_filter : DFSDM filter handle. + * @retval None + */ +void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter) +{ + uint32_t index = 0; + + if(hdfsdm_filter == &haudio_in_dfsdm_leftfilter) + { + DmaLeftRecBuffCplt = 1; + } + else + { + DmaRightRecBuffCplt = 1; + } + if((DmaLeftRecBuffCplt == 1) && (DmaRightRecBuffCplt == 1)) + { + for(index = (ScratchSize/2) ; index < ScratchSize; index++) + { + hAudioIn.pRecBuf[AppBuffTrigger] = (uint16_t)(SaturaLH((pScratchBuff[0][index] >> 8), -32760, 32760)); + hAudioIn.pRecBuf[AppBuffTrigger + 1] = (uint16_t)(SaturaLH((pScratchBuff[1][index] >> 8), -32760, 32760)); + AppBuffTrigger +=2; + } + DmaLeftRecBuffCplt = 0; + DmaRightRecBuffCplt = 0; + } + + /* Call Half Transfer Complete callback */ + if((AppBuffTrigger == hAudioIn.RecSize/2) && (AppBuffHalf == 0)) + { + AppBuffHalf = 1; + BSP_AUDIO_IN_HalfTransfer_CallBack(); + } + /* Call Transfer Complete callback */ + if(AppBuffTrigger == hAudioIn.RecSize) + { + /* Reset Application Buffer Trigger */ + AppBuffTrigger = 0; + AppBuffHalf = 0; + /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ + BSP_AUDIO_IN_TransferComplete_CallBack(); + } +} + +/** + * @brief Half regular conversion complete callback. + * @param hdfsdm_filter : DFSDM filter handle. + * @retval None + */ +void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter) +{ + uint32_t index = 0; + + if(hdfsdm_filter == &haudio_in_dfsdm_leftfilter) + { + DmaLeftRecHalfBuffCplt = 1; + } + else + { + DmaRightRecHalfBuffCplt = 1; + } + if((DmaLeftRecHalfBuffCplt == 1) && (DmaRightRecHalfBuffCplt == 1)) + { + for(index = 0; index < ScratchSize/2; index++) + { + hAudioIn.pRecBuf[AppBuffTrigger] = (int16_t)(SaturaLH((pScratchBuff[0][index] >> 8), -32760, 32760)); + hAudioIn.pRecBuf[AppBuffTrigger + 1] = (int16_t)(SaturaLH((pScratchBuff[1][index] >> 8), -32760, 32760)); + AppBuffTrigger +=2; + } + DmaLeftRecHalfBuffCplt = 0; + DmaRightRecHalfBuffCplt = 0; + } + + /* Call Half Transfer Complete callback */ + if((AppBuffTrigger == hAudioIn.RecSize/2) && (AppBuffHalf == 0)) + { + AppBuffHalf = 1; + BSP_AUDIO_IN_HalfTransfer_CallBack(); + } + /* Call Transfer Complete callback */ + if(AppBuffTrigger == hAudioIn.RecSize) + { + /* Reset Application Buffer Trigger */ + AppBuffTrigger = 0; + AppBuffHalf = 0; + /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ + BSP_AUDIO_IN_TransferComplete_CallBack(); + } +} + +/** + * @brief User callback when record buffer is filled. + * @retval None + */ +__weak void BSP_AUDIO_IN_TransferComplete_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Manages the DMA Half Transfer complete event. + * @retval None + */ +__weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void) +{ + /* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled + to prepare the next buffer pointer and its size. */ +} + +/** + * @brief Audio IN Error callback function. + * @retval None + */ +__weak void BSP_AUDIO_IN_Error_Callback(void) +{ + /* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +} + +/** + * @brief Initialize BSP_AUDIO_IN MSP. + * @retval None + */ +__weak void BSP_AUDIO_IN_MspInit(void) +{ + /* MSP channels initialization */ + DFSDMx_ChannelMspInit(); + /* MSP filters initialization */ + DFSDMx_FilterMspInit(); +} + +/** + * @brief DeInitialize BSP_AUDIO_IN MSP. + * @retval None + */ +__weak void BSP_AUDIO_IN_MspDeInit(void) +{ + /* MSP channels initialization */ + DFSDMx_ChannelMspDeInit(); + /* MSP filters initialization */ + DFSDMx_FilterMspDeInit(); +} + +/** + * @brief Clock Config. + * @param hdfsdm_filter: might be required to set audio peripheral predivider if any. + * @param AudioFreq: Audio frequency used to play the audio stream. + * @param Params + * @note This API is called by BSP_AUDIO_IN_Init() + * Being __weak it can be overwritten by the application + * @retval None + */ +__weak void BSP_AUDIO_IN_ClockConfig(DFSDM_Filter_HandleTypeDef *hdfsdm_filter, uint32_t AudioFreq, void *Params) +{ + RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; + + HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); + + /* Set the PLL configuration according to the audio frequency */ + if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) + { + /* Configure PLLSAI prescalers */ + /* PLLI2S_VCO: VCO_429M + SAI_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 429/2 = 214.5 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ = 214.5/19 = 11.289 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 429; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 2; + rcc_ex_clk_init_struct.PLLI2SDivQ = 19; + + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + + } + else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_32K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */ + { + /* SAI clock config + PLLI2S_VCO: VCO_344M + SAI_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 344/7 = 49.142 Mhz + SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ = 49.142/1 = 49.142 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2; + rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 344; + rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 7; + rcc_ex_clk_init_struct.PLLI2SDivQ = 1; + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); + } + + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_DFSDM1_AUDIO; + rcc_ex_clk_init_struct.Dfsdm1AudioClockSelection = RCC_DFSDM1AUDIOCLKSOURCE_SAI2; + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); +} + +/******************************************************************************* + Static Functions +*******************************************************************************/ +/** + * @brief Initialize the Digital Filter for Sigma-Delta Modulators interface (DFSDM). + * @param AudioFreq: Audio frequency to be used to set correctly the DFSDM peripheral. + * @note Channel output Clock Divider and Filter Oversampling are calculated as follow: + * - Clock_Divider = CLK(input DFSDM)/CLK(micro) with + * 1MHZ < CLK(micro) < 3.2MHZ (TYP 2.4MHZ for MP34DT01TR) + * - Oversampling = CLK(input DFSDM)/(Clock_Divider * AudioFreq) + * @retval AUDIO_OK if correct communication, else wrong communication + */ +static uint8_t DFSDMx_Init(uint32_t AudioFreq) +{ + /*####CHANNEL 1####*/ + __HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(&haudio_in_dfsdm_leftchannel); + haudio_in_dfsdm_leftchannel.Instance = DFSDM1_Channel1; + haudio_in_dfsdm_leftchannel.Init.OutputClock.Activation = ENABLE; + haudio_in_dfsdm_leftchannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO; + /* Set the DFSDM clock OUT audio frequency configuration */ + haudio_in_dfsdm_leftchannel.Init.OutputClock.Divider = DFSDM_CLOCK_DIVIDER(AudioFreq); + haudio_in_dfsdm_leftchannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS; + haudio_in_dfsdm_leftchannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE; + haudio_in_dfsdm_leftchannel.Init.Input.Pins = DFSDM_CHANNEL_SAME_CHANNEL_PINS; + /* Request to sample stable data for LEFT micro on Rising edge */ + haudio_in_dfsdm_leftchannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_RISING; + haudio_in_dfsdm_leftchannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL; + haudio_in_dfsdm_leftchannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_FASTSINC_ORDER; + haudio_in_dfsdm_leftchannel.Init.Awd.Oversampling = 10; + haudio_in_dfsdm_leftchannel.Init.Offset = 0; + haudio_in_dfsdm_leftchannel.Init.RightBitShift = DFSDM_RIGHT_BIT_SHIFT(AudioFreq); + if(HAL_OK != HAL_DFSDM_ChannelInit(&haudio_in_dfsdm_leftchannel)) + { + return AUDIO_ERROR; + } + + /*####FILTER 0####*/ + __HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&haudio_in_dfsdm_leftfilter); + haudio_in_dfsdm_leftfilter.Instance = AUDIO_DFSDMx_LEFT_FILTER; + haudio_in_dfsdm_leftfilter.Init.RegularParam.Trigger = DFSDM_FILTER_SW_TRIGGER; + haudio_in_dfsdm_leftfilter.Init.RegularParam.FastMode = ENABLE; + haudio_in_dfsdm_leftfilter.Init.RegularParam.DmaMode = ENABLE; + haudio_in_dfsdm_leftfilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER; + haudio_in_dfsdm_leftfilter.Init.InjectedParam.ScanMode = ENABLE; + haudio_in_dfsdm_leftfilter.Init.InjectedParam.DmaMode = DISABLE; + haudio_in_dfsdm_leftfilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM1_TRGO; + haudio_in_dfsdm_leftfilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_RISING_EDGE; + haudio_in_dfsdm_leftfilter.Init.FilterParam.SincOrder = DFSDM_FILTER_ORDER(AudioFreq); + /* Set the DFSDM Filters Oversampling to have correct sample rate */ + haudio_in_dfsdm_leftfilter.Init.FilterParam.Oversampling = DFSDM_OVER_SAMPLING(AudioFreq); + haudio_in_dfsdm_leftfilter.Init.FilterParam.IntOversampling = 1; + if(HAL_OK != HAL_DFSDM_FilterInit(&haudio_in_dfsdm_leftfilter)) + { + return AUDIO_ERROR; + } + + /* Configure injected channel */ + if(HAL_OK != HAL_DFSDM_FilterConfigRegChannel(&haudio_in_dfsdm_leftfilter, DFSDM_CHANNEL_1, DFSDM_CONTINUOUS_CONV_ON)) + { + return AUDIO_ERROR; + } + + /*####CHANNEL 0####*/ + __HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(&haudio_in_dfsdm_rightchannel); + haudio_in_dfsdm_rightchannel.Instance = DFSDM1_Channel0; + haudio_in_dfsdm_rightchannel.Init.OutputClock.Activation = ENABLE; + haudio_in_dfsdm_rightchannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO; + /* Set the DFSDM clock OUT audio frequency configuration */ + haudio_in_dfsdm_rightchannel.Init.OutputClock.Divider = DFSDM_CLOCK_DIVIDER(AudioFreq); + haudio_in_dfsdm_rightchannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS; + haudio_in_dfsdm_rightchannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE; + haudio_in_dfsdm_rightchannel.Init.Input.Pins = DFSDM_CHANNEL_FOLLOWING_CHANNEL_PINS; + /* Request to sample stable data for RIGHT micro on Falling edge */ + haudio_in_dfsdm_rightchannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_FALLING; + haudio_in_dfsdm_rightchannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL; + haudio_in_dfsdm_rightchannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_FASTSINC_ORDER; + haudio_in_dfsdm_rightchannel.Init.Awd.Oversampling = 10; + haudio_in_dfsdm_rightchannel.Init.Offset = 0; + haudio_in_dfsdm_rightchannel.Init.RightBitShift = DFSDM_RIGHT_BIT_SHIFT(AudioFreq); + if(HAL_OK != HAL_DFSDM_ChannelInit(&haudio_in_dfsdm_rightchannel)) + { + return AUDIO_ERROR; + } + + /*####FILTER 1####*/ + __HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&haudio_in_dfsdm_rightfilter); + haudio_in_dfsdm_rightfilter.Instance = AUDIO_DFSDMx_RIGHT_FILTER; + haudio_in_dfsdm_rightfilter.Init.RegularParam.Trigger = DFSDM_FILTER_SYNC_TRIGGER; + haudio_in_dfsdm_rightfilter.Init.RegularParam.FastMode = ENABLE; + haudio_in_dfsdm_rightfilter.Init.RegularParam.DmaMode = ENABLE; + haudio_in_dfsdm_rightfilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER; + haudio_in_dfsdm_rightfilter.Init.InjectedParam.ScanMode = DISABLE; + haudio_in_dfsdm_rightfilter.Init.InjectedParam.DmaMode = DISABLE; + haudio_in_dfsdm_rightfilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM1_TRGO; + haudio_in_dfsdm_rightfilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_RISING_EDGE; + haudio_in_dfsdm_rightfilter.Init.FilterParam.SincOrder = DFSDM_FILTER_ORDER(AudioFreq); + /* Set the DFSDM Filters Oversampling to have correct sample rate */ + haudio_in_dfsdm_rightfilter.Init.FilterParam.Oversampling = DFSDM_OVER_SAMPLING(AudioFreq); + haudio_in_dfsdm_rightfilter.Init.FilterParam.IntOversampling = 1; + if(HAL_OK != HAL_DFSDM_FilterInit(&haudio_in_dfsdm_rightfilter)) + { + return AUDIO_ERROR; + } + /* Configure injected channel */ + if(HAL_OK != HAL_DFSDM_FilterConfigRegChannel(&haudio_in_dfsdm_rightfilter, DFSDM_CHANNEL_0, DFSDM_CONTINUOUS_CONV_ON)) + { + return AUDIO_ERROR; + } + + return AUDIO_OK; +} + +/** + * @brief De-initialize the Digital Filter for Sigma-Delta Modulators interface (DFSDM). + * @retval AUDIO_OK if correct communication, else wrong communication + */ +static uint8_t DFSDMx_DeInit(void) +{ + /* De-initializes the DFSDM filters to allow access to DFSDM internal registers */ + if(HAL_OK != HAL_DFSDM_FilterDeInit(&haudio_in_dfsdm_leftfilter)) + { + return AUDIO_ERROR; + } + + if(HAL_OK != HAL_DFSDM_FilterDeInit(&haudio_in_dfsdm_rightfilter)) + { + return AUDIO_ERROR; + } + + /* De-initializes the DFSDM channels to allow access to DFSDM internal registers */ + if(HAL_OK != HAL_DFSDM_ChannelDeInit(&haudio_in_dfsdm_leftchannel)) + { + return AUDIO_ERROR; + } + + if(HAL_OK != HAL_DFSDM_ChannelDeInit(&haudio_in_dfsdm_rightchannel)) + { + return AUDIO_ERROR; + } + + return AUDIO_OK; +} + +/** + * @brief Initialize the DFSDM channel MSP. + * @retval None + */ +static void DFSDMx_ChannelMspInit(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /* Enable DFSDM clock */ + AUDIO_DFSDMx_CLK_ENABLE(); + + /* Enable GPIO clock */ + AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_CLK_ENABLE(); + + /* DFSDM pins configuration: DFSDM_CKOUT, DMIC_DATIN pins ------------------*/ + GPIO_InitStruct.Pin = AUDIO_DFSDMx_CKOUT_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = AUDIO_DFSDMx_CKOUT_AF; + HAL_GPIO_Init(AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_PORT, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = AUDIO_DFSDMx_DMIC_DATIN_PIN; + GPIO_InitStruct.Alternate = AUDIO_DFSDMx_DMIC_DATIN_AF; + HAL_GPIO_Init(AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_PORT, &GPIO_InitStruct); +} + +/** + * @brief DeInitialize the DFSDM channel MSP. + * @retval None + */ +static void DFSDMx_ChannelMspDeInit(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /* DFSDM pins configuration: DFSDM_CKOUT, DMIC_DATIN pins ------------------*/ + GPIO_InitStruct.Pin = AUDIO_DFSDMx_CKOUT_PIN | AUDIO_DFSDMx_DMIC_DATIN_PIN; + HAL_GPIO_DeInit(AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_PORT, GPIO_InitStruct.Pin); +} + +/** + * @brief Initialize the DFSDM filter MSP. + * @retval None + */ +static void DFSDMx_FilterMspInit(void) +{ + /* Enable DFSDM clock */ + AUDIO_DFSDMx_CLK_ENABLE(); + + /* Enable the DMA clock */ + AUDIO_DFSDMx_DMAx_CLK_ENABLE(); + + hdma_dfsdm_left.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_dfsdm_left.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_dfsdm_left.Init.MemInc = DMA_MINC_ENABLE; + hdma_dfsdm_left.Init.PeriphDataAlignment = AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE; + hdma_dfsdm_left.Init.MemDataAlignment = AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE; + hdma_dfsdm_left.Init.Mode = DMA_CIRCULAR; + hdma_dfsdm_left.Init.Priority = DMA_PRIORITY_HIGH; + hdma_dfsdm_left.Instance = DMA2_Stream0; + hdma_dfsdm_left.Init.Channel = AUDIO_DFSDMx_DMAx_LEFT_CHANNEL; + + /* Associate the DMA handle */ + __HAL_LINKDMA(&haudio_in_dfsdm_leftfilter, hdmaReg, hdma_dfsdm_left); + + /* Reset DMA handle state */ + __HAL_DMA_RESET_HANDLE_STATE(&hdma_dfsdm_left); + + /* Configure the DMA Channel */ + HAL_DMA_Init(&hdma_dfsdm_left); + + /* DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_DFSDMx_DMAx_LEFT_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_DFSDMx_DMAx_LEFT_IRQ); + + + /* Configure the hdma_dfsdmReg handle parameters */ + hdma_dfsdm_right.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_dfsdm_right.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_dfsdm_right.Init.MemInc = DMA_MINC_ENABLE; + hdma_dfsdm_right.Init.PeriphDataAlignment = AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE; + hdma_dfsdm_right.Init.MemDataAlignment = AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE; + hdma_dfsdm_right.Init.Mode = DMA_CIRCULAR; + hdma_dfsdm_right.Init.Priority = DMA_PRIORITY_HIGH; + hdma_dfsdm_right.Instance = DMA2_Stream5; + hdma_dfsdm_right.Init.Channel = AUDIO_DFSDMx_DMAx_RIGHT_CHANNEL; + + /* Associate the DMA handle */ + __HAL_LINKDMA(&haudio_in_dfsdm_rightfilter, hdmaReg, hdma_dfsdm_right); + + /* Reset DMA handle state */ + __HAL_DMA_RESET_HANDLE_STATE(&hdma_dfsdm_right); + + /* Configure the DMA Channel */ + HAL_DMA_Init(&hdma_dfsdm_right); + + /* DMA IRQ Channel configuration */ + HAL_NVIC_SetPriority(AUDIO_DFSDMx_DMAx_RIGHT_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_DFSDMx_DMAx_RIGHT_IRQ); +} + +/** + * @brief DeInitialize the DFSDM filter MSP. + * @retval None + */ +static void DFSDMx_FilterMspDeInit(void) +{ + /* Configure the DMA Channel */ + HAL_DMA_DeInit(&hdma_dfsdm_left); + HAL_DMA_DeInit(&hdma_dfsdm_right); +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_audio.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_audio.h new file mode 100644 index 00000000..b51ce696 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_audio.h @@ -0,0 +1,323 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_audio.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_eval_audio.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_EVAL_AUDIO_H +#define __STM32F769I_EVAL_AUDIO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include audio component Driver */ +#include "../Components/wm8994/wm8994.h" + +#if defined(USE_LCD_HDMI) +/* Include ADV7533 HDMI Driver IC driver code */ +#include "../Components/adv7533/adv7533.h" +#endif /* USE_LCD_HDMI */ + +#include "stm32f769i_eval.h" +#include + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @addtogroup STM32F769I_EVAL_AUDIO + * @{ + */ + +/** @defgroup STM32F769I_EVAL_AUDIO_Exported_Types STM32F769I_EVAL_AUDIO Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_AUDIO_Exported_Constants STM32F769I_EVAL_AUDIO Exported Constants + * @{ + */ + +/** @defgroup BSP_Audio_Out_Option BSP Audio Out Option + * @{ + */ +#define BSP_AUDIO_OUT_CIRCULARMODE ((uint32_t)0x00000001) /* BUFFER CIRCULAR MODE */ +#define BSP_AUDIO_OUT_NORMALMODE ((uint32_t)0x00000002) /* BUFFER NORMAL MODE */ +#define BSP_AUDIO_OUT_STEREOMODE ((uint32_t)0x00000004) /* STEREO MODE */ +#define BSP_AUDIO_OUT_MONOMODE ((uint32_t)0x00000008) /* MONO MODE */ +/** + * @} + */ +/** @defgroup BSP_Audio_Sample_Rate BSP Audio Sample Rate + * @{ + */ +#define BSP_AUDIO_FREQUENCY_96K SAI_AUDIO_FREQUENCY_96K +#define BSP_AUDIO_FREQUENCY_48K SAI_AUDIO_FREQUENCY_48K +#define BSP_AUDIO_FREQUENCY_44K SAI_AUDIO_FREQUENCY_44K +#define BSP_AUDIO_FREQUENCY_32K SAI_AUDIO_FREQUENCY_32K +#define BSP_AUDIO_FREQUENCY_22K SAI_AUDIO_FREQUENCY_22K +#define BSP_AUDIO_FREQUENCY_16K SAI_AUDIO_FREQUENCY_16K +#define BSP_AUDIO_FREQUENCY_11K SAI_AUDIO_FREQUENCY_11K +#define BSP_AUDIO_FREQUENCY_8K SAI_AUDIO_FREQUENCY_8K +/** + * @} + */ + +/*------------------------------------------------------------------------------ + USER SAI defines parameters + -----------------------------------------------------------------------------*/ +/** CODEC_AudioFrame_SLOT_TDMMode In W8994 codec the Audio frame contains 4 slots : TDM Mode + * TDM format : + * +------------------|------------------|--------------------|-------------------+ + * | CODEC_SLOT0 Left | CODEC_SLOT1 Left | CODEC_SLOT0 Right | CODEC_SLOT1 Right | + * +------------------------------------------------------------------------------+ + */ +/* To have 2 separate audio stream in Both headphone and speaker the 4 slot must be activated */ +#define CODEC_AUDIOFRAME_SLOT_0123 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_2 | SAI_SLOTACTIVE_3 +/* To have an audio stream in headphone only SAI Slot 0 and Slot 2 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_02 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_2 +/* To have an audio stream in speaker only SAI Slot 1 and Slot 3 must be activated */ +#define CODEC_AUDIOFRAME_SLOT_13 SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_3 + +/* SAI peripheral configuration defines */ +#define AUDIO_SAIx SAI2_Block_B +#define AUDIO_SAIx_CLK_ENABLE() __HAL_RCC_SAI2_CLK_ENABLE() +#define AUDIO_SAIx_CLK_DISABLE() __HAL_RCC_SAI2_CLK_DISABLE() +#define AUDIO_SAIx_SCK_AF GPIO_AF8_SAI2 +#define AUDIO_SAIx_FS_SD_MCLK_AF GPIO_AF10_SAI2 + +#define AUDIO_SAIx_MCLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() +#define AUDIO_SAIx_MCLK_GPIO_PORT GPIOE +#define AUDIO_SAIx_MCLK_PIN GPIO_PIN_6 +#define AUDIO_SAIx_SCK_SD_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define AUDIO_SAIx_SCK_SD_GPIO_PORT GPIOA +#define AUDIO_SAIx_SCK_PIN GPIO_PIN_2 +#define AUDIO_SAIx_SD_PIN GPIO_PIN_0 +#define AUDIO_SAIx_FS_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE() +#define AUDIO_SAIx_FS_GPIO_PORT GPIOG +#define AUDIO_SAIx_FS_PIN GPIO_PIN_9 + + +/* SAI DMA Stream definitions */ +#define AUDIO_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_SAIx_DMAx_STREAM DMA2_Stream6 +#define AUDIO_SAIx_DMAx_CHANNEL DMA_CHANNEL_3 +#define AUDIO_SAIx_DMAx_IRQ DMA2_Stream6_IRQn +#define AUDIO_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD +#define AUDIO_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD +#define DMA_MAX_SZE 0xFFFF + +#define AUDIO_SAIx_DMAx_IRQHandler DMA2_Stream6_IRQHandler + +/* Select the interrupt preemption priority for the DMA interrupt */ +#define AUDIO_OUT_IRQ_PREPRIO ((uint32_t)0x0E) + +/*------------------------------------------------------------------------------ + AUDIO IN CONFIGURATION +------------------------------------------------------------------------------*/ +/* DFSDM Configuration defines */ +#define AUDIO_DFSDMx_LEFT_CHANNEL DFSDM_CHANNEL_1 +#define AUDIO_DFSDMx_RIGHT_CHANNEL DFSDM_CHANNEL_0 +#define AUDIO_DFSDMx_LEFT_FILTER DFSDM1_Filter0 +#define AUDIO_DFSDMx_RIGHT_FILTER DFSDM1_Filter1 +#define AUDIO_DFSDMx_CLK_ENABLE() __HAL_RCC_DFSDM_CLK_ENABLE() +#define AUDIO_DFSDMx_CKOUT_PIN GPIO_PIN_3 +#define AUDIO_DFSDMx_DMIC_DATIN_PIN GPIO_PIN_6 +#define AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_PORT GPIOD +#define AUDIO_DFSDMx_CKOUT_DMIC_DATIN_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() +#define AUDIO_DFSDMx_DMIC_DATIN_AF GPIO_AF10_DFSDM1 +#define AUDIO_DFSDMx_CKOUT_AF GPIO_AF3_DFSDM1 + +/* DFSDM DMA Right and Left channels definitions */ +#define AUDIO_DFSDMx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() +#define AUDIO_DFSDMx_DMAx_LEFT_CHANNEL DMA_CHANNEL_8 +#define AUDIO_DFSDMx_DMAx_RIGHT_CHANNEL DMA_CHANNEL_8 +#define AUDIO_DFSDMx_DMAx_LEFT_IRQ DMA2_Stream0_IRQn +#define AUDIO_DFSDMx_DMAx_RIGHT_IRQ DMA2_Stream5_IRQn +#define AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_WORD +#define AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_WORD + +#define AUDIO_DFSDM_DMAx_LEFT_IRQHandler DMA2_Stream0_IRQHandler +#define AUDIO_DFSDM_DMAx_RIGHT_IRQHandler DMA2_Stream5_IRQHandler + +/* Select the interrupt preemption priority and subpriority for the IT/DMA interrupt */ +#define AUDIO_IN_IRQ_PREPRIO ((uint32_t)0x0F) + + +/*------------------------------------------------------------------------------ + CONFIGURATION: Audio Driver Configuration parameters +------------------------------------------------------------------------------*/ + +#define AUDIODATA_SIZE 2 /* 16-bits audio data size */ + +/* Audio status definition */ +#define AUDIO_OK ((uint8_t)0) +#define AUDIO_ERROR ((uint8_t)1) +#define AUDIO_TIMEOUT ((uint8_t)2) + +/* AudioFreq * DataSize (2 bytes) * NumChannels (Stereo: 2) */ +#define DEFAULT_AUDIO_IN_FREQ I2S_AUDIOFREQ_16K +#define DEFAULT_AUDIO_IN_BIT_RESOLUTION ((uint8_t)16) +#define DEFAULT_AUDIO_IN_CHANNEL_NBR ((uint8_t)2) /* Mono = 1, Stereo = 2 */ +#define DEFAULT_AUDIO_IN_VOLUME ((uint16_t)64) + +/*------------------------------------------------------------------------------ + OPTIONAL Configuration defines parameters +------------------------------------------------------------------------------*/ + +/* Delay for the Codec to be correctly reset */ +#define CODEC_RESET_DELAY ((uint8_t)5) + + +/*------------------------------------------------------------------------------ + OUTPUT DEVICES definition +------------------------------------------------------------------------------*/ +/* Alias on existing output devices to adapt for 2 headphones output */ +#define OUTPUT_DEVICE_HEADPHONE1 OUTPUT_DEVICE_HEADPHONE +#define OUTPUT_DEVICE_HEADPHONE2 OUTPUT_DEVICE_SPEAKER /* Headphone2 is connected to Speaker output of the wm8994 */ +#define OUTPUT_DEVICE_HDMI OUTPUT_DEVICE_ADV7533_HDMI +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_AUDIO_Exported_Variables STM32F769I_EVAL_AUDIO Exported Variables + * @{ + */ + /** + * @} + */ + +/** @defgroup STM32F769I_EVAL_AUDIO_Exported_Macros STM32F769I_EVAL_AUDIO Exported Macros + * @{ + */ +#define DMA_MAX(x) (((x) <= DMA_MAX_SZE)? (x):DMA_MAX_SZE) +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_AUDIO_OUT_Exported_Functions STM32F769I_EVAL_AUDIO_OUT Exported Functions + * @{ + */ +uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq); +void BSP_AUDIO_OUT_DeInit(void); +uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size); +void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size); +uint8_t BSP_AUDIO_OUT_Pause(void); +uint8_t BSP_AUDIO_OUT_Resume(void); +uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option); +uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume); +void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq); +void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot); +uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd); +uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output); + +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function is called when the requested data has been completely transferred.*/ +void BSP_AUDIO_OUT_TransferComplete_CallBack(void); + +/* This function is called when half of the requested buffer has been transferred. */ +void BSP_AUDIO_OUT_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_OUT_Error_CallBack(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params); +void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params); +void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_AUDIO_IN_Exported_Functions STM32F769I_EVAL_AUDIO_IN Exported Functions + * @{ + */ +uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); +uint8_t BSP_AUDIO_IN_AllocScratch (int32_t *pScratch, uint32_t size); +void BSP_AUDIO_IN_DeInit(void); +uint8_t BSP_AUDIO_IN_Record(uint16_t *pData, uint32_t Size); +uint8_t BSP_AUDIO_IN_Stop(void); +uint8_t BSP_AUDIO_IN_Pause(void); +uint8_t BSP_AUDIO_IN_Resume(void); + +/* User Callbacks: user has to implement these functions in his code if they are needed. */ +/* This function should be implemented by the user application. + It is called into this driver when the current buffer is filled to prepare the next + buffer pointer and its size. */ +void BSP_AUDIO_IN_TransferComplete_CallBack(void); +void BSP_AUDIO_IN_HalfTransfer_CallBack(void); + +/* This function is called when an Interrupt due to transfer error on or peripheral + error occurs. */ +void BSP_AUDIO_IN_Error_Callback(void); + +/* These function can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_AUDIO_IN_ClockConfig(DFSDM_Filter_HandleTypeDef *hdfsdm_filter, uint32_t AudioFreq, void *Params); +void BSP_AUDIO_IN_MspInit(void); +void BSP_AUDIO_IN_MspDeInit(void); +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_EVAL_AUDIO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_camera.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_camera.c new file mode 100644 index 00000000..2b0e0bc9 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_camera.c @@ -0,0 +1,689 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_camera.c + * @author MCD Application Team + * @brief This file includes the driver for Camera modules mounted on + * STM32F769I-EVAL evaluation board. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* File Info: ------------------------------------------------------------------ + User NOTES +1. How to use this driver: +-------------------------- + - This driver is used to drive the camera. + - The S5K5CAG component driver MUST be included with this driver. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the camera using the BSP_CAMERA_Init() function. + o Start the camera capture/snapshot using the CAMERA_Start() function. + o Suspend, resume or stop the camera capture using the following functions: + - BSP_CAMERA_Suspend() + - BSP_CAMERA_Resume() + - BSP_CAMERA_Stop() + + + Options + o Increase or decrease on the fly the brightness and/or contrast + using the following function: + - BSP_CAMERA_ContrastBrightnessConfig + o Add a special effect on the fly using the following functions: + - BSP_CAMERA_BlackWhiteConfig() + - BSP_CAMERA_ColorEffectConfig() + +------------------------------------------------------------------------------*/ + +/* Dependencies +- stm32f769i_eval.c +- stm32f7xx_hal_dcmi.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- s5k5cag.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval_camera.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_CAMERA STM32F769I_EVAL CAMERA + * @{ + */ + +/** @defgroup STM32F769I_EVAL_CAMERA_Private_TypesDefinitions STM32F769I Eval Camera Private TypesDef + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_CAMERA_Private_Defines STM32F769I Eval Camera Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_CAMERA_Private_Macros STM32F769I Eval Camera Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_CAMERA_Imported_Variables STM32F769I Eval Camera Imported Variables + * @{ + */ +/** + * @brief DMA2D handle variable + */ +extern DMA2D_HandleTypeDef hdma2d_eval; +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_CAMERA_Private_Variables STM32F769I Eval Camera Private Variables + * @{ + */ +DCMI_HandleTypeDef hDcmiEval; +CAMERA_DrvTypeDef *CameraDrv; + +/* Camera current resolution naming (QQVGA, VGA, ...) */ +uint32_t CameraCurrentResolution; + +/* Camera image rotation on LCD Displayed frame buffer */ +uint32_t CameraRotation = CAMERA_ROTATION_INVALID; + +static uint32_t CameraHwAddress; + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_CAMERA_Private_FunctionPrototypes STM32F769I Eval Camera Private Prototypes + * @{ + */ +static uint32_t GetSize(uint32_t Resolution); +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_CAMERA_Public_Functions STM32F769I Eval Camera Public Functions + * @{ + */ + +/** + * @brief Set Camera image rotation on LCD Displayed frame buffer. + * @param rotation : uint32_t rotation of camera image in preview buffer sent to LCD + * need to be of type Camera_ImageRotationTypeDef + * @retval Camera status + */ +uint8_t BSP_CAMERA_SetRotation(uint32_t rotation) +{ + uint8_t status = CAMERA_ERROR; + + if(rotation < CAMERA_ROTATION_INVALID) + { + /* Set Camera image rotation on LCD Displayed frame buffer */ + CameraRotation = rotation; + status = CAMERA_OK; + } + + return status; +} + +/** + * @brief Get Camera image rotation on LCD Displayed frame buffer. + * @retval rotation : uint32_t value of type Camera_ImageRotationTypeDef + */ +uint32_t BSP_CAMERA_GetRotation(void) +{ + return(CameraRotation); +} + +/** + * @brief Initializes the camera. + * @param Resolution : camera sensor requested resolution (x, y) : standard resolution + * naming QQVGA, QVGA, VGA ... + * @retval Camera status + */ +uint8_t BSP_CAMERA_Init(uint32_t Resolution) +{ + DCMI_HandleTypeDef *phdcmi; + uint8_t status = CAMERA_ERROR; + + /* Get the DCMI handle structure */ + phdcmi = &hDcmiEval; + + /*** Configures the DCMI to interface with the camera module ***/ + /* DCMI configuration */ + phdcmi->Init.CaptureRate = DCMI_CR_ALL_FRAME; + phdcmi->Init.HSPolarity = DCMI_HSPOLARITY_HIGH; + phdcmi->Init.SynchroMode = DCMI_SYNCHRO_HARDWARE; + phdcmi->Init.VSPolarity = DCMI_VSPOLARITY_HIGH; + phdcmi->Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B; + phdcmi->Init.PCKPolarity = DCMI_PCKPOLARITY_RISING; + + phdcmi->Instance = DCMI; + + /* Configure IO functionalities for CAMERA detect pin */ + BSP_IO_Init(); + /* Apply Camera Module hardware reset */ + BSP_CAMERA_HwReset(); + + /* Check if the CAMERA Module is plugged on board */ + if(BSP_IO_ReadPin(CAM_PLUG_PIN) == BSP_IO_PIN_SET) + { + status = CAMERA_NOT_DETECTED; + return status; /* Exit with error */ + } + + /* Read ID of Camera module via I2C */ + if (s5k5cag_ReadID(CAMERA_I2C_ADDRESS) == S5K5CAG_ID) + { + /* Initialize the camera driver structure */ + CameraDrv = &s5k5cag_drv; + CameraHwAddress = CAMERA_I2C_ADDRESS; + + /* DCMI Initialization */ + BSP_CAMERA_MspInit(&hDcmiEval, NULL); + HAL_DCMI_Init(phdcmi); + + /* Camera Module Initialization via I2C to the wanted 'Resolution' */ + CameraDrv->Init(CameraHwAddress, Resolution); + + CameraCurrentResolution = Resolution; + + /* Return CAMERA_OK status */ + status = CAMERA_OK; + } + else if(ov5640_ReadID(CAMERA_I2C_ADDRESS_2) == OV5640_ID) + { + /* Initialize the camera driver structure */ + CameraDrv = &ov5640_drv; + CameraHwAddress = CAMERA_I2C_ADDRESS_2; + + /* DCMI Initialization */ + BSP_CAMERA_MspInit(&hDcmiEval, NULL); + HAL_DCMI_Init(phdcmi); + + /* Camera Module Initialization via I2C to the wanted 'Resolution' */ + CameraDrv->Init(CameraHwAddress, Resolution); + + CameraCurrentResolution = Resolution; + + /* Return CAMERA_OK status */ + status = CAMERA_OK; + } + else + { + /* Return CAMERA_NOT_SUPPORTED status */ + status = CAMERA_NOT_SUPPORTED; + } + + return status; +} + + +/** + * @brief DeInitializes the camera. + * @retval Camera status + */ +uint8_t BSP_CAMERA_DeInit(void) +{ + hDcmiEval.Instance = DCMI; + + HAL_DCMI_DeInit(&hDcmiEval); + BSP_CAMERA_MspDeInit(&hDcmiEval, NULL); + return CAMERA_OK; +} + +/** + * @brief Starts the camera capture in continuous mode. + * @param buff: pointer to the camera output buffer + */ +void BSP_CAMERA_ContinuousStart(uint8_t *buff) +{ + /* Start the camera capture */ + HAL_DCMI_Start_DMA(&hDcmiEval, DCMI_MODE_CONTINUOUS, (uint32_t)buff, GetSize(CameraCurrentResolution)); +} + +/** + * @brief Starts the camera capture in snapshot mode. + * @param buff: pointer to the camera output buffer + */ +void BSP_CAMERA_SnapshotStart(uint8_t *buff) +{ + /* Start the camera capture */ + HAL_DCMI_Start_DMA(&hDcmiEval, DCMI_MODE_SNAPSHOT, (uint32_t)buff, GetSize(CameraCurrentResolution)); +} + +/** + * @brief Suspend the CAMERA capture + */ +void BSP_CAMERA_Suspend(void) +{ + /* Suspend the Camera Capture */ + HAL_DCMI_Suspend(&hDcmiEval); +} + +/** + * @brief Resume the CAMERA capture + */ +void BSP_CAMERA_Resume(void) +{ + /* Start the Camera Capture */ + HAL_DCMI_Resume(&hDcmiEval); +} + +/** + * @brief Stop the CAMERA capture + * @retval Camera status + */ +uint8_t BSP_CAMERA_Stop(void) +{ + uint8_t status = CAMERA_ERROR; + + if(HAL_DCMI_Stop(&hDcmiEval) == HAL_OK) + { + status = CAMERA_OK; + } + + /* Set Camera in Power Down */ + BSP_CAMERA_PwrDown(); + + return status; +} + +/** + * @brief CANERA hardware reset + */ +void BSP_CAMERA_HwReset(void) +{ + /* Camera sensor RESET sequence */ + BSP_IO_ConfigPin(RSTI_PIN, IO_MODE_OUTPUT); + BSP_IO_ConfigPin(XSDN_PIN, IO_MODE_OUTPUT); + + /* Assert the camera STANDBY pin (active high) */ + BSP_IO_WritePin(XSDN_PIN, BSP_IO_PIN_SET); + + /* Assert the camera RSTI pin (active low) */ + BSP_IO_WritePin(RSTI_PIN, BSP_IO_PIN_RESET); + + HAL_Delay(100); /* RST and XSDN signals asserted during 100ms */ + + /* De-assert the camera STANDBY pin (active high) */ + BSP_IO_WritePin(XSDN_PIN, BSP_IO_PIN_RESET); + + HAL_Delay(3); /* RST de-asserted and XSDN asserted during 3ms */ + + /* De-assert the camera RSTI pin (active low) */ + BSP_IO_WritePin(RSTI_PIN, BSP_IO_PIN_SET); + + HAL_Delay(6); /* RST de-asserted during 3ms */ +} + +/** + * @brief CAMERA power down + */ +void BSP_CAMERA_PwrDown(void) +{ + /* Camera power down sequence */ + BSP_IO_ConfigPin(RSTI_PIN, IO_MODE_OUTPUT); + BSP_IO_ConfigPin(XSDN_PIN, IO_MODE_OUTPUT); + + /* De-assert the camera STANDBY pin (active high) */ + BSP_IO_WritePin(XSDN_PIN, BSP_IO_PIN_RESET); + + /* Assert the camera RSTI pin (active low) */ + BSP_IO_WritePin(RSTI_PIN, BSP_IO_PIN_RESET); +} + +/** + * @brief Configures the camera contrast and brightness. + * @param contrast_level: Contrast level + * This parameter can be one of the following values: + * @arg CAMERA_CONTRAST_LEVEL4: for contrast +2 + * @arg CAMERA_CONTRAST_LEVEL3: for contrast +1 + * @arg CAMERA_CONTRAST_LEVEL2: for contrast 0 + * @arg CAMERA_CONTRAST_LEVEL1: for contrast -1 + * @arg CAMERA_CONTRAST_LEVEL0: for contrast -2 + * @param brightness_level: Contrast level + * This parameter can be one of the following values: + * @arg CAMERA_BRIGHTNESS_LEVEL4: for brightness +2 + * @arg CAMERA_BRIGHTNESS_LEVEL3: for brightness +1 + * @arg CAMERA_BRIGHTNESS_LEVEL2: for brightness 0 + * @arg CAMERA_BRIGHTNESS_LEVEL1: for brightness -1 + * @arg CAMERA_BRIGHTNESS_LEVEL0: for brightness -2 + */ +void BSP_CAMERA_ContrastBrightnessConfig(uint32_t contrast_level, uint32_t brightness_level) +{ + if(CameraDrv->Config != NULL) + { + CameraDrv->Config(CameraHwAddress, CAMERA_CONTRAST_BRIGHTNESS, contrast_level, brightness_level); + } +} + +/** + * @brief Configures the camera white balance. + * @param Mode: black_white mode + * This parameter can be one of the following values: + * @arg CAMERA_BLACK_WHITE_BW + * @arg CAMERA_BLACK_WHITE_NEGATIVE + * @arg CAMERA_BLACK_WHITE_BW_NEGATIVE + * @arg CAMERA_BLACK_WHITE_NORMAL + */ +void BSP_CAMERA_BlackWhiteConfig(uint32_t Mode) +{ + if(CameraDrv->Config != NULL) + { + CameraDrv->Config(CameraHwAddress, CAMERA_BLACK_WHITE, Mode, 0); + } +} + +/** + * @brief Configures the camera color effect. + * @param Effect: Color effect + * This parameter can be one of the following values: + * @arg CAMERA_COLOR_EFFECT_NONE + * @arg CAMERA_COLOR_EFFECT_BLUE + * @arg CAMERA_COLOR_EFFECT_GREEN + * @arg CAMERA_COLOR_EFFECT_RED + * @arg CAMERA_COLOR_EFFECT_ANTIQUE + */ +void BSP_CAMERA_ColorEffectConfig(uint32_t Effect) +{ + if(CameraDrv->Config != NULL) + { + CameraDrv->Config(CameraHwAddress, CAMERA_COLOR_EFFECT, Effect, 0); + } +} + +/** + * @brief Get the capture size in pixels unit. + * @param Resolution: the current resolution. + * @retval capture size in pixels unit. + */ +static uint32_t GetSize(uint32_t Resolution) +{ + uint32_t size = 0; + + /* Get capture size */ + switch (Resolution) + { + case CAMERA_R160x120: + { + size = 0x2580; + } + break; + case CAMERA_R320x240: + { + size = 0x9600; + } + break; + case CAMERA_R480x272: + { + size = 0xFF00; + } + break; + case CAMERA_R640x480: + { + size = 0x25800; + } + break; + default: + { + break; + } + } + + return size; +} + +/** + * @brief Initializes the DCMI MSP. + * @param hdcmi: HDMI handle + * @param Params : pointer on additional configuration parameters, can be NULL. + */ +__weak void BSP_CAMERA_MspInit(DCMI_HandleTypeDef *hdcmi, void *Params) +{ + static DMA_HandleTypeDef hdma_eval; + GPIO_InitTypeDef gpio_init_structure; + + /*** Enable peripherals and GPIO clocks ***/ + /* Enable DCMI clock */ + __HAL_RCC_DCMI_CLK_ENABLE(); + + /* Enable DMA2 clock */ + __HAL_RCC_DMA2_CLK_ENABLE(); + + /* Enable GPIO clocks */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + + /*** Configure the GPIO ***/ + /* Configure DCMI GPIO as alternate function */ + gpio_init_structure.Pin = GPIO_PIN_4 | GPIO_PIN_6; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOA, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_7; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOB, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 |\ + GPIO_PIN_9 | GPIO_PIN_11; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOC, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_3 | GPIO_PIN_6; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + gpio_init_structure.Pin = GPIO_PIN_5 | GPIO_PIN_6; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = GPIO_AF13_DCMI; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /*** Configure the DMA ***/ + /* Set the parameters to be configured */ + hdma_eval.Init.Channel = DMA_CHANNEL_1; + hdma_eval.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_eval.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_eval.Init.MemInc = DMA_MINC_ENABLE; + hdma_eval.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + hdma_eval.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + hdma_eval.Init.Mode = DMA_CIRCULAR; + hdma_eval.Init.Priority = DMA_PRIORITY_HIGH; + hdma_eval.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_eval.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + hdma_eval.Init.MemBurst = DMA_MBURST_SINGLE; + hdma_eval.Init.PeriphBurst = DMA_PBURST_SINGLE; + + hdma_eval.Instance = DMA2_Stream1; + + /* Associate the initialized DMA handle to the DCMI handle */ + __HAL_LINKDMA(hdcmi, DMA_Handle, hdma_eval); + + /*** Configure the NVIC for DCMI and DMA ***/ + /* NVIC configuration for DCMI transfer complete interrupt */ + HAL_NVIC_SetPriority(DCMI_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DCMI_IRQn); + + /* NVIC configuration for DMA2D transfer complete interrupt */ + HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn); + + /* Configure the DMA stream */ + HAL_DMA_Init(hdcmi->DMA_Handle); +} + +/** + * @brief DeInitializes the DCMI MSP. + * @param hdcmi: HDMI handle + * @param Params : pointer on additional configuration parameters, can be NULL. + */ +__weak void BSP_CAMERA_MspDeInit(DCMI_HandleTypeDef *hdcmi, void *Params) +{ + /* Disable NVIC for DCMI transfer complete interrupt */ + HAL_NVIC_DisableIRQ(DCMI_IRQn); + + /* Disable NVIC for DMA2 transfer complete interrupt */ + HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn); + + /* Configure the DMA stream */ + HAL_DMA_DeInit(hdcmi->DMA_Handle); + + /* Disable DCMI clock */ + __HAL_RCC_DCMI_CLK_DISABLE(); + + /* GPIO pins clock and DMA clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Line event callback + * @param hdcmi: pointer to the DCMI handle + */ +void HAL_DCMI_LineEventCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_LineEventCallback(); +} + +/** + * @brief Line Event callback. + */ +__weak void BSP_CAMERA_LineEventCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_LineEventCallback could be implemented in the user file + */ +} + +/** + * @brief VSYNC event callback + * @param hdcmi: pointer to the DCMI handle + */ +void HAL_DCMI_VsyncEventCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_VsyncEventCallback(); +} + +/** + * @brief VSYNC Event callback. + */ +__weak void BSP_CAMERA_VsyncEventCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_VsyncEventCallback could be implemented in the user file + */ +} + +/** + * @brief Frame event callback + * @param hdcmi: pointer to the DCMI handle + */ +void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_FrameEventCallback(); +} + +/** + * @brief Frame Event callback. + */ +__weak void BSP_CAMERA_FrameEventCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_FrameEventCallback could be implemented in the user file + */ +} + +/** + * @brief Error callback + * @param hdcmi: pointer to the DCMI handle + */ +void HAL_DCMI_ErrorCallback(DCMI_HandleTypeDef *hdcmi) +{ + BSP_CAMERA_ErrorCallback(); +} + +/** + * @brief Error callback. + */ +__weak void BSP_CAMERA_ErrorCallback(void) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_DCMI_ErrorCallback could be implemented in the user file + */ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_camera.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_camera.h new file mode 100644 index 00000000..214ef65c --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_camera.h @@ -0,0 +1,166 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_camera.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_eval_camera.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_EVAL_CAMERA_H +#define __STM32F769I_EVAL_CAMERA_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include Camera component Driver */ +#include "../Components/s5k5cag/s5k5cag.h" +#include "../Components/ov5640/ov5640.h" + +/* Include IO Driver */ +#include "stm32f769i_eval_io.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @addtogroup STM32F769I_EVAL_CAMERA + * @{ + */ + +/** @defgroup STM32F769I_EVAL_CAMERA_Exported_Types CAMERA Exported Types + * @{ + */ + +/** + * @brief Camera State structures definition + */ +#define CAMERA_OK 0x00 +#define CAMERA_ERROR 0x01 +#define CAMERA_TIMEOUT 0x02 +#define CAMERA_NOT_DETECTED 0x03 +#define CAMERA_NOT_SUPPORTED 0x04 + + +/** + * @brief Camera Image rotation definition + * in frame buffer for LCD Display. + */ +#define CAMERA_NO_ROTATION 0x00 +#define CAMERA_ROTATION_90 0x01 +#define CAMERA_ROTATION_INVALID 0x02 + +#define RESOLUTION_R160x120 CAMERA_R160x120 /* QQVGA Resolution */ +#define RESOLUTION_R320x240 CAMERA_R320x240 /* QVGA Resolution */ +#define RESOLUTION_R480x272 CAMERA_R480x272 /* 480x272 Resolution */ +#define RESOLUTION_R640x480 CAMERA_R640x480 /* VGA Resolution */ + +#define CAMERA_VGA_RES_X 640 +#define CAMERA_VGA_RES_Y 480 +#define CAMERA_480x272_RES_X 480 +#define CAMERA_480x272_RES_Y 272 +#define CAMERA_QVGA_RES_X 320 +#define CAMERA_QVGA_RES_Y 240 +#define CAMERA_QQVGA_RES_X 160 +#define CAMERA_QQVGA_RES_Y 120 +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_CAMERA_Exported_Constants CAMERA Exported Constants + * @{ + */ + #define BSP_CAMERA_IRQHandler DCMI_IRQHandler + #define BSP_CAMERA_DMA_IRQHandler DMA2_Stream1_IRQHandler +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_CAMERA_Exported_Functions CAMERA Exported Functions + * @{ + */ +uint8_t BSP_CAMERA_Init(uint32_t Resolution); +uint8_t BSP_CAMERA_DeInit(void); +void BSP_CAMERA_ContinuousStart(uint8_t *buff); +void BSP_CAMERA_SnapshotStart(uint8_t *buff); +void BSP_CAMERA_Suspend(void); +void BSP_CAMERA_Resume(void); +uint8_t BSP_CAMERA_Stop(void); +void BSP_CAMERA_HwReset(void); +void BSP_CAMERA_PwrDown(void); +void BSP_CAMERA_LineEventCallback(void); +void BSP_CAMERA_VsyncEventCallback(void); +void BSP_CAMERA_FrameEventCallback(void); +void BSP_CAMERA_ErrorCallback(void); + +/* Camera features functions prototype */ +void BSP_CAMERA_ContrastBrightnessConfig(uint32_t contrast_level, uint32_t brightness_level); +void BSP_CAMERA_BlackWhiteConfig(uint32_t Mode); +void BSP_CAMERA_ColorEffectConfig(uint32_t Effect); + + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_CAMERA_MspInit(DCMI_HandleTypeDef *hdcmi, void *Params); +void BSP_CAMERA_MspDeInit(DCMI_HandleTypeDef *hdcmi, void *Params); +uint8_t BSP_CAMERA_SetRotation(uint32_t rotation); +uint32_t BSP_CAMERA_GetRotation(void); + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_EVAL_CAMERA_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_eeprom.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_eeprom.c new file mode 100644 index 00000000..a3f2dc61 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_eeprom.c @@ -0,0 +1,476 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_eeprom.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage an I2C M24LR64 + * EEPROM memory. + @verbatim + To be able to use this driver, the switch EE_M24LR64 must be defined + in your toolchain compiler preprocessor + + =================================================================== + Notes: + - The I2C EEPROM memory (M24LR64) is available on separate daughter + board ANT7-M24LR-A, which is not provided with the STM32F769I_EVAL + board. + To use this driver you have to connect the ANT7-M24LR-A to CN2 + connector of STM32F769I_EVAL board. + =================================================================== + + It implements a high level communication layer for read and write + from/to this memory. The needed STM32F7xx hardware resources (I2C and + GPIO) are defined in stm32f769i_eval.h file, and the initialization is + performed in EEPROM_IO_Init() function declared in stm32f769i_eval.c + file. + You can easily tailor this driver to any other development board, + by just adapting the defines for hardware resources and + EEPROM_IO_Init() function. + + @note In this driver, basic read and write functions (BSP_EEPROM_ReadBuffer() + and BSP_EEPROM_WritePage()) use DMA mode to perform the data + transfer to/from EEPROM memory. + + @note Regarding BSP_EEPROM_WritePage(), it is an optimized function to perform + small write (less than 1 page) BUT the number of bytes (combined to write start address) must not + cross the EEPROM page boundary. This function can only writes into + the boundaries of an EEPROM page. + This function doesn't check on boundaries condition (in this driver + the function BSP_EEPROM_WriteBuffer() which calls BSP_EEPROM_WritePage() is + responsible of checking on Page boundaries). + + + +-----------------------------------------------------------------+ + | Pin assignment for M24LR64 EEPROM | + +---------------------------------------+-----------+-------------+ + | STM32F7xx I2C Pins | EEPROM | Pin | + +---------------------------------------+-----------+-------------+ + | . | E0(GND) | 1 (0V) | + | . | AC0 | 2 | + | . | AC1 | 3 | + | . | VSS | 4 (0V) | + | SDA | SDA | 5 | + | SCL | SCL | 6 | + | . | E1(GND) | 7 (0V) | + | . | VDD | 8 (3.3V) | + +---------------------------------------+-----------+-------------+ + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f769i_eval.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval_eeprom.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_EEPROM STM32F769I_EVAL EEPROM + * @brief This file includes the I2C EEPROM driver of STM32F769I-EVAL evaluation board. + * @{ + */ + +/** @defgroup STM32F769I_EVAL_EEPROM_Private_Types EEPROM Private Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_EEPROM_Private_Defines EEPROM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_EEPROM_Private_Macros EEPROM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_EEPROM_Private_Variables EEPROM Private Variables + * @{ + */ +__IO uint16_t EEPROMAddress = 0; +__IO uint16_t EEPROMDataRead; +__IO uint8_t EEPROMDataWrite; +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_EEPROM_Private_Function_Prototypes EEPROM Private Functions Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_EEPROM_Private_Functions EEPROM Private Functions + * @{ + */ + +/** + * @brief Initializes peripherals used by the I2C EEPROM driver. + * @note There are 2 different versions of M24LR64 (A01 & A02). + * Then try to connect on 1st one (EEPROM_I2C_ADDRESS_A01) + * and if problem, check the 2nd one (EEPROM_I2C_ADDRESS_A02) + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) + */ +uint32_t BSP_EEPROM_Init(void) +{ + /* I2C Initialization */ + EEPROM_IO_Init(); + + /* Select the EEPROM address for A01 and check if OK */ + EEPROMAddress = EEPROM_I2C_ADDRESS_A01; + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + /* Select the EEPROM address for A02 and check if OK */ + EEPROMAddress = EEPROM_I2C_ADDRESS_A02; + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + return EEPROM_FAIL; + } + } + return EEPROM_OK; +} + +/** + * @brief DeInitializes the EEPROM. + * @retval EEPROM state + */ +uint8_t BSP_EEPROM_DeInit(void) +{ + /* I2C won't be disabled because common to other functionalities */ + return EEPROM_OK; +} + +/** + * @brief Reads a block of data from the EEPROM. + * @param pBuffer: pointer to the buffer that receives the data read from + * the EEPROM. + * @param ReadAddr: EEPROM's internal address to start reading from. + * @param NumByteToRead: pointer to the variable holding number of bytes to + * be read from the EEPROM. + * + * @note The variable pointed by NumByteToRead is reset to 0 when all the + * data are read from the EEPROM. Application should monitor this + * variable in order know when the transfer is complete. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead) +{ + uint32_t buffersize = *NumByteToRead; + + /* Set the pointer to the Number of data to be read. This pointer will be used + by the DMA Transfer Completer interrupt Handler in order to reset the + variable to 0. User should check on this variable in order to know if the + DMA transfer has been complete or not. */ + EEPROMDataRead = *NumByteToRead; + + if(EEPROM_IO_ReadData(EEPROMAddress, ReadAddr, pBuffer, buffersize) != HAL_OK) + { + BSP_EEPROM_TIMEOUT_UserCallback(); + return EEPROM_FAIL; + } + + /* If all operations OK, return EEPROM_OK (0) */ + return EEPROM_OK; +} + +/** + * @brief Writes more than one byte to the EEPROM with a single WRITE cycle. + * + * @note The number of bytes (combined to write start address) must not + * cross the EEPROM page boundary. This function can only write into + * the boundaries of an EEPROM page. + * This function doesn't check on boundaries condition (in this driver + * the function BSP_EEPROM_WriteBuffer() which calls BSP_EEPROM_WritePage() is + * responsible of checking on Page boundaries). + * + * @param pBuffer: pointer to the buffer containing the data to be written to + * the EEPROM. + * @param WriteAddr: EEPROM's internal address to write to. + * @param NumByteToWrite: pointer to the variable holding number of bytes to + * be written into the EEPROM. + * + * @note The variable pointed by NumByteToWrite is reset to 0 when all the + * data are written to the EEPROM. Application should monitor this + * variable in order know when the transfer is complete. + * + * @note This function just configure the communication and enable the DMA + * channel to transfer data. Meanwhile, the user application may perform + * other tasks in parallel. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite) +{ + uint32_t buffersize = *NumByteToWrite; + uint32_t status = EEPROM_OK; + + /* Set the pointer to the Number of data to be written. This pointer will be used + by the DMA Transfer Completer interrupt Handler in order to reset the + variable to 0. User should check on this variable in order to know if the + DMA transfer has been complete or not. */ + EEPROMDataWrite = *NumByteToWrite; + + if(EEPROM_IO_WriteData(EEPROMAddress, WriteAddr, pBuffer, buffersize) != HAL_OK) + { + BSP_EEPROM_TIMEOUT_UserCallback(); + status = EEPROM_FAIL; + } + + if(BSP_EEPROM_WaitEepromStandbyState() != EEPROM_OK) + { + return EEPROM_FAIL; + } + + /* If all operations OK, return EEPROM_OK (0) */ + return status; +} + +/** + * @brief Writes buffer of data to the I2C EEPROM. + * @param pBuffer: pointer to the buffer containing the data to be written + * to the EEPROM. + * @param WriteAddr: EEPROM's internal address to write to. + * @param NumByteToWrite: number of bytes to write to the EEPROM. + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WriteBuffer(uint8_t *pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite) +{ + uint16_t numofpage = 0, numofsingle = 0, count = 0; + uint16_t addr = 0; + uint8_t dataindex = 0; + uint32_t status = EEPROM_OK; + + addr = WriteAddr % EEPROM_PAGESIZE; + count = EEPROM_PAGESIZE - addr; + numofpage = NumByteToWrite / EEPROM_PAGESIZE; + numofsingle = NumByteToWrite % EEPROM_PAGESIZE; + + /* If WriteAddr is EEPROM_PAGESIZE aligned */ + if(addr == 0) + { + /* If NumByteToWrite < EEPROM_PAGESIZE */ + if(numofpage == 0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + /* Start writing data */ + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + /* If NumByteToWrite > EEPROM_PAGESIZE */ + else + { + while(numofpage--) + { + /* Store the number of data to be written */ + dataindex = EEPROM_PAGESIZE; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + + WriteAddr += EEPROM_PAGESIZE; + pBuffer += EEPROM_PAGESIZE; + } + + if(numofsingle!=0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + } + /* If WriteAddr is not EEPROM_PAGESIZE aligned */ + else + { + /* If NumByteToWrite < EEPROM_PAGESIZE */ + if(numofpage== 0) + { + /* If the number of data to be written is more than the remaining space + in the current page: */ + if(NumByteToWrite > count) + { + /* Store the number of data to be written */ + dataindex = count; + /* Write the data contained in same page */ + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + + /* Store the number of data to be written */ + dataindex = (NumByteToWrite - count); + /* Write the remaining data in the following page */ + status = BSP_EEPROM_WritePage((uint8_t*)(pBuffer + count), (WriteAddr + count), (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + else + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + /* If NumByteToWrite > EEPROM_PAGESIZE */ + else + { + NumByteToWrite -= count; + numofpage = NumByteToWrite / EEPROM_PAGESIZE; + numofsingle = NumByteToWrite % EEPROM_PAGESIZE; + + if(count != 0) + { + /* Store the number of data to be written */ + dataindex = count; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + WriteAddr += count; + pBuffer += count; + } + + while(numofpage--) + { + /* Store the number of data to be written */ + dataindex = EEPROM_PAGESIZE; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + WriteAddr += EEPROM_PAGESIZE; + pBuffer += EEPROM_PAGESIZE; + } + if(numofsingle != 0) + { + /* Store the number of data to be written */ + dataindex = numofsingle; + status = BSP_EEPROM_WritePage(pBuffer, WriteAddr, (uint8_t*)(&dataindex)); + if(status != EEPROM_OK) + { + return status; + } + } + } + } + + /* If all operations OK, return EEPROM_OK (0) */ + return EEPROM_OK; +} + +/** + * @brief Wait for EEPROM Standby state. + * + * @note This function allows to wait and check that EEPROM has finished the + * last operation. It is mostly used after Write operation: after receiving + * the buffer to be written, the EEPROM may need additional time to actually + * perform the write operation. During this time, it doesn't answer to + * I2C packets addressed to it. Once the write operation is complete + * the EEPROM responds to its address. + * + * @retval EEPROM_OK (0) if operation is correctly performed, else return value + * different from EEPROM_OK (0) or the timeout user callback. + */ +uint32_t BSP_EEPROM_WaitEepromStandbyState(void) +{ + /* Check if the maximum allowed number of trials has bee reached */ + if(EEPROM_IO_IsDeviceReady(EEPROMAddress, EEPROM_MAX_TRIALS) != HAL_OK) + { + /* If the maximum number of trials has been reached, exit the function */ + BSP_EEPROM_TIMEOUT_UserCallback(); + return EEPROM_TIMEOUT; + } + return EEPROM_OK; +} + +/** + * @brief Basic management of the timeout situation. + * @retval None + */ +__weak void BSP_EEPROM_TIMEOUT_UserCallback(void) +{ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_eeprom.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_eeprom.h new file mode 100644 index 00000000..138d694a --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_eeprom.h @@ -0,0 +1,138 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_eeprom.h + * @author MCD Application Team + * @brief This file contains all the functions prototypes for + * the stm32f769i_eval_eeprom.c firmware driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F756G_EVAL_EEPROM_H +#define __STM32F756G_EVAL_EEPROM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @addtogroup STM32F769I_EVAL_EEPROM + * @brief This file includes the I2C EEPROM driver of STM32F769I-EVAL evaluation board. + * @{ + */ + +/** @defgroup STM32F769I_EVAL_EEPROM_Exported_Types EEPROM_ Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_EEPROM_Exported_Constants EEPROM Exported Constants + * @{ + */ +/* EEPROM hardware address and page size */ +#define EEPROM_PAGESIZE ((uint8_t)4) +#define EEPROM_MAX_SIZE ((uint16_t)0x2000) /* 64Kbit */ + + +/* Maximum number of trials for EEPROM_WaitEepromStandbyState() function */ +#define EEPROM_MAX_TRIALS ((uint32_t)3000) + +#define EEPROM_OK ((uint32_t)0) +#define EEPROM_FAIL ((uint32_t)1) +#define EEPROM_TIMEOUT ((uint32_t)2) +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_EEPROM_Exported_Macros EEPROM Exported Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_EEPROM_Exported_Functions EEPROM Exported Functions + * @{ + */ +uint32_t BSP_EEPROM_Init(void); +uint8_t BSP_EEPROM_DeInit(void); +uint32_t BSP_EEPROM_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead); +uint32_t BSP_EEPROM_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite); +uint32_t BSP_EEPROM_WriteBuffer(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite); +uint32_t BSP_EEPROM_WaitEepromStandbyState(void); + +/* USER Callbacks: This function is declared as __weak in EEPROM driver and + should be implemented into user application. + BSP_EEPROM_TIMEOUT_UserCallback() function is called whenever a timeout condition + occurs during communication (waiting on an event that doesn't occur, bus + errors, busy devices ...). */ +void BSP_EEPROM_TIMEOUT_UserCallback(void); + +/* Link function for I2C EEPROM peripheral */ +void EEPROM_IO_Init(void); +HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t *pBuffer, uint32_t BufferSize); +HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_EVAL_EEPROM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_io.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_io.c new file mode 100644 index 00000000..d21ace5b --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_io.c @@ -0,0 +1,335 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_io.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the IO pins + * on STM32F769I-EVAL evaluation board. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the IO module of the STM32F769I-EVAL evaluation + board. + - The MFXSTM32L152 IO expander device component driver must be included with this + driver in order to run the IO functionalities commanded by the IO expander (MFX) + device mounted on the evaluation board. + + Driver description: + ------------------- + + Initialization steps: + o Initialize the IO module using the BSP_IO_Init() function. This + function includes the MSP layer hardware resources initialization and the + communication layer configuration to start the IO functionalities use. + + + IO functionalities use + o The IO pin mode is configured when calling the function BSP_IO_ConfigPin(), you + must specify the desired IO mode by choosing the "IO_ModeTypedef" parameter + predefined value. + o If an IO pin is used in interrupt mode, the function BSP_IO_ITGetStatus() is + needed to get the interrupt status. To clear the IT pending bits, you should + call the function BSP_IO_ITClear() with specifying the IO pending bit to clear. + o The IT is handled using the corresponding external interrupt IRQ handler, + the user IT callback treatment is implemented on the same external interrupt + callback. + o The IRQ_OUT pin (common for all functionalities: JOY, SD, LEDs, etc) can be + configured using the function BSP_IO_ConfigIrqOutPin() + o To get/set an IO pin combination state you can use the functions + BSP_IO_ReadPin()/BSP_IO_WritePin() or the function BSP_IO_TogglePin() to toggle the pin + state. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f769i_eval.h +- mfxstm32l152.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval_io.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_IO STM32F769I_EVAL IO + * @{ + */ + +/** @defgroup STM32F769I_EVAL_IO_Private_Types_Definitions IO Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_IO_Private_Defines IO Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_IO_Private_Macros IO Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_IO_Private_Variables IO Private Variables + * @{ + */ +static IO_DrvTypeDef *IoDrv = NULL; +static uint8_t mfxstm32l152Identifier; + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_IO_Private_Functions_Prototypes IO Private Functions Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_IO_Private_Functions IO Private Functions + * @{ + */ + +/** + * @brief Initializes and configures the IO functionalities and configures all + * necessary hardware resources (MFX, ...). + * @note BSP_IO_Init() is using HAL_Delay() function to ensure that MFXSTM32L152 + * IO Expander is correctly reset. HAL_Delay() function provides accurate + * delay (in milliseconds) based on variable incremented in SysTick ISR. + * This implies that if BSP_IO_Init() is called from a peripheral ISR process, + * then the SysTick interrupt must have higher priority (numerically lower) + * than the peripheral interrupt. Otherwise the caller ISR process will be blocked. + * @retval IO_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_IO_Init(void) +{ + uint8_t ret = IO_OK; + + if (IoDrv == NULL) /* Checks if MFX initialization never done */ + { + /* Read ID and verify the MFX is ready */ + mfxstm32l152Identifier = mfxstm32l152_io_drv.ReadID(IO_I2C_ADDRESS); + if((mfxstm32l152Identifier == MFXSTM32L152_ID_1) || (mfxstm32l152Identifier == MFXSTM32L152_ID_2)) + { + /* Initialize the IO driver structure */ + IoDrv = &mfxstm32l152_io_drv; + + /* Initialize MFX */ + IoDrv->Init(IO_I2C_ADDRESS); + IoDrv->Start(IO_I2C_ADDRESS, IO_PIN_ALL); + } + else + { + ret = IO_ERROR; + } + } + else + { + /* MFX initialization already done : do nothing */ + } + + return ret; +} + +/** + * @brief DeInit allows Mfx Initialization to be executed again + * @note BSP_IO_Init() has no effect if the IoDrv is already initialized + * BSP_IO_DeInit() allows to erase the pointer such to allow init to be effective + * @retval IO_OK + */ +uint8_t BSP_IO_DeInit(void) +{ + IoDrv = NULL; + return IO_OK; +} + +/** + * @brief Gets the selected pins IT status. + * @param IoPin: Selected pins to check the status. + * This parameter can be any combination of the IO pins. + * @retval IO_OK if read status OK. Other value if error. + */ +uint32_t BSP_IO_ITGetStatus(uint32_t IoPin) +{ + /* Return the IO Pin IT status */ + return (IoDrv->ITStatus(IO_I2C_ADDRESS, IoPin)); +} + +/** + * @brief Clears all the IO IT pending bits. + * @retval None + */ +void BSP_IO_ITClear(void) +{ + /* Clear all IO IT pending bits */ + IoDrv->ClearIT(IO_I2C_ADDRESS, MFXSTM32L152_GPIO_PINS_ALL); +} + +/** + * @brief Clear only one or a selection of IO IT pending bits. + * @param IO_Pins_To_Clear : MFX IRQ status IO pin to clear (or combination of several IOs) + */ +void BSP_IO_ITClearPin(uint32_t IO_Pins_To_Clear) +{ + /* Clear only the selected list of IO IT pending bits */ + IoDrv->ClearIT(IO_I2C_ADDRESS, IO_Pins_To_Clear); +} + +/** + * @brief Configures the IO pin(s) according to IO mode structure value. + * @param IoPin: IO pin(s) to be configured. + * This parameter can be one of the following values: + * @arg MFXSTM32L152_GPIO_PIN_x: where x can be from 0 to 23. + * @param IoMode: IO pin mode to configure + * This parameter can be one of the following values: + * @arg IO_MODE_INPUT + * @arg IO_MODE_OUTPUT + * @arg IO_MODE_IT_RISING_EDGE + * @arg IO_MODE_IT_FALLING_EDGE + * @arg IO_MODE_IT_LOW_LEVEL + * @arg IO_MODE_IT_HIGH_LEVEL + * @arg IO_MODE_ANALOG + * @arg IO_MODE_OFF + * @arg IO_MODE_INPUT_PU, + * @arg IO_MODE_INPUT_PD, + * @arg IO_MODE_OUTPUT_OD, + * @arg IO_MODE_OUTPUT_OD_PU, + * @arg IO_MODE_OUTPUT_OD_PD, + * @arg IO_MODE_OUTPUT_PP, + * @arg IO_MODE_OUTPUT_PP_PU, + * @arg IO_MODE_OUTPUT_PP_PD, + * @arg IO_MODE_IT_RISING_EDGE_PU + * @arg IO_MODE_IT_FALLING_EDGE_PU + * @arg IO_MODE_IT_LOW_LEVEL_PU + * @arg IO_MODE_IT_HIGH_LEVEL_PU + * @arg IO_MODE_IT_RISING_EDGE_PD + * @arg IO_MODE_IT_FALLING_EDGE_PD + * @arg IO_MODE_IT_LOW_LEVEL_PD + * @arg IO_MODE_IT_HIGH_LEVEL_PD + * @retval IO_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_IO_ConfigPin(uint32_t IoPin, IO_ModeTypedef IoMode) +{ + /* Configure the selected IO pin(s) mode */ + IoDrv->Config(IO_I2C_ADDRESS, IoPin, IoMode); + + return IO_OK; +} + +/** + * @brief Sets the IRQ_OUT pin polarity and type + * @param IoIrqOutPinPolarity: High/Low + * @param IoIrqOutPinType: OpenDrain/PushPull + * @retval OK + */ +uint8_t BSP_IO_ConfigIrqOutPin(uint8_t IoIrqOutPinPolarity, uint8_t IoIrqOutPinType) +{ + if((mfxstm32l152Identifier == MFXSTM32L152_ID_1) || (mfxstm32l152Identifier == MFXSTM32L152_ID_2)) + { + /* Initialize the IO driver structure */ + mfxstm32l152_SetIrqOutPinPolarity(IO_I2C_ADDRESS, IoIrqOutPinPolarity); + mfxstm32l152_SetIrqOutPinType(IO_I2C_ADDRESS, IoIrqOutPinType); + } + + return IO_OK; +} + +/** + * @brief Sets the selected pins state. + * @param IoPin: Selected pins to write. + * This parameter can be any combination of the IO pins. + * @param PinState: New pins state to write + * @retval None + */ +void BSP_IO_WritePin(uint32_t IoPin, BSP_IO_PinStateTypeDef PinState) +{ + /* Set the Pin state */ + IoDrv->WritePin(IO_I2C_ADDRESS, IoPin, PinState); +} + +/** + * @brief Gets the selected pins current state. + * @param IoPin: Selected pins to read. + * This parameter can be any combination of the IO pins. + * @retval The current pins state + */ +uint32_t BSP_IO_ReadPin(uint32_t IoPin) +{ + return(IoDrv->ReadPin(IO_I2C_ADDRESS, IoPin)); +} + +/** + * @brief Toggles the selected pins state. + * @param IoPin: Selected pins to toggle. + * This parameter can be any combination of the IO pins. + * @note This function is only used to toggle one pin in the same time + * @retval None + */ +void BSP_IO_TogglePin(uint32_t IoPin) +{ + /* Toggle the current pin state */ + if(IoDrv->ReadPin(IO_I2C_ADDRESS, IoPin) != 0) /* Set */ + { + IoDrv->WritePin(IO_I2C_ADDRESS, IoPin, 0); /* Reset */ + } + else + { + IoDrv->WritePin(IO_I2C_ADDRESS, IoPin, 1); /* Set */ + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_io.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_io.h new file mode 100644 index 00000000..90c06234 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_io.h @@ -0,0 +1,157 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_io.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_eval_io.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_EVAL_IO_H +#define __STM32F769I_EVAL_IO_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval.h" +/* Include IO component driver */ +#include "../Components/mfxstm32l152/mfxstm32l152.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @addtogroup STM32F769I_EVAL_IO + * @{ + */ + +/** @defgroup STM32F769I_EVAL_IO_Exported_Types IO Exported Types + * @{ + */ + +typedef enum +{ + BSP_IO_PIN_RESET = 0, + BSP_IO_PIN_SET = 1 +}BSP_IO_PinStateTypeDef; + +typedef enum +{ + IO_OK = 0, + IO_ERROR = 1, + IO_TIMEOUT = 2 +}IO_StatusTypeDef; +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_IO_Exported_Constants IO Exported Constants + * @{ + */ +#define IO_PIN_0 ((uint32_t)0x0001) +#define IO_PIN_1 ((uint32_t)0x0002) +#define IO_PIN_2 ((uint32_t)0x0004) +#define IO_PIN_3 ((uint32_t)0x0008) +#define IO_PIN_4 ((uint32_t)0x0010) +#define IO_PIN_5 ((uint32_t)0x0020) +#define IO_PIN_6 ((uint32_t)0x0040) +#define IO_PIN_7 ((uint32_t)0x0080) +#define IO_PIN_8 ((uint32_t)0x0100) +#define IO_PIN_9 ((uint32_t)0x0200) +#define IO_PIN_10 ((uint32_t)0x0400) +#define IO_PIN_11 ((uint32_t)0x0800) +#define IO_PIN_12 ((uint32_t)0x1000) +#define IO_PIN_13 ((uint32_t)0x2000) +#define IO_PIN_14 ((uint32_t)0x4000) +#define IO_PIN_15 ((uint32_t)0x8000) +#define IO_PIN_16 ((uint32_t)0x010000) +#define IO_PIN_17 ((uint32_t)0x020000) +#define IO_PIN_18 ((uint32_t)0x040000) +#define IO_PIN_19 ((uint32_t)0x080000) +#define IO_PIN_20 ((uint32_t)0x100000) +#define IO_PIN_21 ((uint32_t)0x200000) +#define IO_PIN_22 ((uint32_t)0x400000) +#define IO_PIN_23 ((uint32_t)0x800000) +#define IO_PIN_ALL ((uint32_t)0xFFFFFF) +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_IO_Exported_Macro IO Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_IO_Exported_Functions IO Exported Functions + * @{ + */ +uint8_t BSP_IO_Init(void); +uint8_t BSP_IO_DeInit(void); +uint8_t BSP_IO_ConfigIrqOutPin(uint8_t IoIrqOutPinPolarity, uint8_t IoIrqOutPinType); +uint32_t BSP_IO_ITGetStatus(uint32_t IoPin); +void BSP_IO_ITClear(void); +void BSP_IO_ITClearPin(uint32_t IO_Pins_To_Clear); +uint8_t BSP_IO_ConfigPin(uint32_t IoPin, IO_ModeTypedef IoMode); +void BSP_IO_WritePin(uint32_t IoPin, BSP_IO_PinStateTypeDef PinState); +uint32_t BSP_IO_ReadPin(uint32_t IoPin); +void BSP_IO_TogglePin(uint32_t IoPin); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_EVAL_IO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_lcd.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_lcd.c new file mode 100644 index 00000000..563c3fae --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_lcd.c @@ -0,0 +1,1960 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_lcd.c + * @author MCD Application Team + * @brief This file includes the driver for Liquid Crystal Display (LCD) module + * mounted on STM32F769I-EVAL evaluation board. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ +/* File Info: ------------------------------------------------------------------ + User NOTES +1. How To use this driver: +-------------------------- + - This driver is used to drive directly in video mode a LCD TFT using the DSI interface. + The following IPs are implied : DSI Host IP block working + in conjunction to the LTDC controller. + - This driver is linked by construction to LCD KoD mounted on board MB1166. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the LCD using the BSP_LCD_Init() function. + o Select the LCD layer to be used using the BSP_LCD_SelectLayer() function. + o Enable the LCD display using the BSP_LCD_DisplayOn() function. + + + Options + o Configure and enable the color keying functionality using the + BSP_LCD_SetColorKeying() function. + o Modify in the fly the transparency and/or the frame buffer address + using the following functions: + - BSP_LCD_SetTransparency() + - BSP_LCD_SetLayerAddress() + + + Display on LCD + o Clear the whole LCD using BSP_LCD_Clear() function or only one specified string + line using the BSP_LCD_ClearStringLine() function. + o Display a character on the specified line and column using the BSP_LCD_DisplayChar() + function or a complete string line using the BSP_LCD_DisplayStringAtLine() function. + o Display a string line on the specified position (x,y in pixel) and align mode + using the BSP_LCD_DisplayStringAtLine() function. + o Draw and fill a basic shapes (dot, line, rectangle, circle, ellipse, .. bitmap) + on LCD using the available set of functions. + +------------------------------------------------------------------------------*/ + +/* Dependencies +- stm32f769i_eval.c +- stm32f769i_eval_sdram.c +- stm32f7xx_hal_dsi.c +- stm32f7xx_hal_ltdc.c +- stm32f7xx_hal_ltdc_ex.c +- stm32f7xx_hal_dma2d.c +- stm32f7xx_hal_rcc_ex.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- otm8009a.c +- adv7533.c +- fonts.h +- font24.c +- font20.c +- font16.c +- font12.c +- font8.c" +EndDependencies */ +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval_lcd.h" +#include "../../../Utilities/Fonts/fonts.h" +#include "../../../Utilities/Fonts/font24.c" +#include "../../../Utilities/Fonts/font20.c" +#include "../../../Utilities/Fonts/font16.c" +#include "../../../Utilities/Fonts/font12.c" +#include "../../../Utilities/Fonts/font8.c" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_LCD STM32F769I_EVAL LCD + * @{ + */ + +/** @defgroup STM32F769I_EVAL_LCD_Private_Defines LCD Private Defines + * @{ + */ + +#if defined(USE_LCD_HDMI) +#define HDMI_ASPECT_RATIO_16_9 ADV7533_ASPECT_RATIO_16_9 +#define HDMI_ASPECT_RATIO_4_3 ADV7533_ASPECT_RATIO_4_3 +#endif /* USE_LCD_HDMI */ +#define LCD_DSI_ID 0x11 +#define LCD_DSI_ID_REG 0xA8 + +static DSI_VidCfgTypeDef hdsivideo_handle; +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LCD_Private_TypesDefinitions LCD Private TypesDefinitions + * @{ + */ + +#if defined(USE_LCD_HDMI) +/** + * @brief DSI timming params used for different HDMI adpater + */ +typedef struct +{ + uint16_t HACT; + uint16_t HSYNC; + uint16_t HBP; + uint16_t HFP; + uint16_t VACT; + uint16_t VSYNC; + uint16_t VBP; + uint16_t VFP; + uint8_t ASPECT_RATIO; + uint8_t RGB_CODING; +} HDMI_FormatTypeDef; + +/** + * @brief DSI packet params used for different HDMI adpater + */ +typedef struct +{ + uint16_t NullPacketSize; + uint16_t NumberOfChunks; + uint16_t PacketSize; +} HDMI_DSIPacketTypeDef; + +/** + * @brief LTDC PLL params used for different HDMI adpater + */ +typedef struct +{ + uint16_t PLLSAIN; + uint16_t PLLSAIR; + uint32_t PCLK; + uint16_t IDF; + uint16_t NDIV; + uint16_t ODF; + uint16_t LaneByteClock; + uint16_t TXEscapeCkdiv; +} HDMI_PLLConfigTypeDef; + +#endif /* USE_LCD_HDMI */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LCD_Private_Macros LCD Private Macros + * @{ + */ +#define ABS(X) ((X) > 0 ? (X) : -(X)) + +#define POLY_X(Z) ((int32_t)((Points + (Z))->X)) +#define POLY_Y(Z) ((int32_t)((Points + (Z))->Y)) +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LCD_Exported_Variables STM32F769I EVAL LCD Exported Variables + * @{ + */ +DMA2D_HandleTypeDef hdma2d_eval; +LTDC_HandleTypeDef hltdc_eval; +DSI_HandleTypeDef hdsi_eval; +uint32_t lcd_x_size = OTM8009A_800X480_WIDTH; +uint32_t lcd_y_size = OTM8009A_800X480_HEIGHT; + +/** + * @} + */ + + +/** @defgroup STM32F769I_EVAL_LCD_Private_Variables LCD Private Variables + * @{ + */ + +#if defined(USE_LCD_HDMI) +/** + * @brief DSI timming used for different HDMI resolution (720x480 and 720x576) + */ +HDMI_FormatTypeDef HDMI_Format[2] = +{ +/* HA HS HB HF VA VS VB VF ASPECT BPP */ + {720, 62, 60, 30, 480, 6, 19, 9, HDMI_ASPECT_RATIO_4_3, LCD_DSI_PIXEL_DATA_FMT_RBG888}, + {720, 64, 68, 12, 576, 5, 39, 5, HDMI_ASPECT_RATIO_16_9, LCD_DSI_PIXEL_DATA_FMT_RBG888} + +}; + +/** + * @brief DSI packet size used for different HDMI resolution (720x480 and 720x576) + */ +HDMI_DSIPacketTypeDef HDMI_DSIPacket[2] = +{ + /* NP NC VP */ + {0, 1, 720}, + {0, 1, 720} +}; + +/** + * @brief LTDC PLL settings used for different HDMI resolution (720x480 and 720x576) + */ +HDMI_PLLConfigTypeDef HDMI_PLLConfig[4] = +{ +/* N DIV Pclk IDF NDIV ODF LBClk TXEscapeCkdiv*/ + {325, 6, 27083, DSI_PLL_IN_DIV5, 65, DSI_PLL_OUT_DIV1, 40625, 3}, + {325, 6, 27083, DSI_PLL_IN_DIV5, 65, DSI_PLL_OUT_DIV1, 40625, 3} + +}; +#endif /* USE_LCD_HDMI */ + +/** + * @brief Default Active LTDC Layer in which drawing is made is LTDC Layer Background + */ +static uint32_t ActiveLayer = LTDC_ACTIVE_LAYER_BACKGROUND; + +/** + * @brief Current Drawing Layer properties variable + */ +static LCD_DrawPropTypeDef DrawProp[LTDC_MAX_LAYER_NUMBER]; +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LCD_Private_FunctionPrototypes LCD Private FunctionPrototypes + * @{ + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c); +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3); +static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex); +static void LL_ConvertLineToARGB8888(void * pSrc, void *pDst, uint32_t xSize, uint32_t ColorMode); +static uint16_t LCD_IO_GetID(void); +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LCD_Exported_Functions LCD Exported Functions + * @{ + */ + +/** + * @brief Initializes the DSI LCD. + * @retval LCD state + */ +uint8_t BSP_LCD_Init(void) +{ + return (BSP_LCD_InitEx(LCD_ORIENTATION_LANDSCAPE)); +} + +/** + * @brief Initializes the DSI LCD. + * The ititialization is done as below: + * - DSI PLL ititialization + * - DSI ititialization + * - LTDC ititialization + * - OTM8009A LCD Display IC Driver ititialization + * @param orientation: LCD_ORIENTATION_PORTRAIT or LCD_ORIENTATION_LANDSCAPE + * @retval LCD state + */ +uint8_t BSP_LCD_InitEx(LCD_OrientationTypeDef orientation) +{ + DSI_PLLInitTypeDef dsiPllInit; + static RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + uint32_t LcdClock = 27429; /*!< LcdClk = 27429 kHz */ + uint16_t read_id = 0; + + uint32_t laneByteClk_kHz = 0; + uint32_t VSA; /*!< Vertical start active time in units of lines */ + uint32_t VBP; /*!< Vertical Back Porch time in units of lines */ + uint32_t VFP; /*!< Vertical Front Porch time in units of lines */ + uint32_t VACT; /*!< Vertical Active time in units of lines = imageSize Y in pixels to display */ + uint32_t HSA; /*!< Horizontal start active time in units of lcdClk */ + uint32_t HBP; /*!< Horizontal Back Porch time in units of lcdClk */ + uint32_t HFP; /*!< Horizontal Front Porch time in units of lcdClk */ + uint32_t HACT; /*!< Horizontal Active time in units of lcdClk = imageSize X in pixels to display */ + + /* Toggle Hardware Reset of the DSI LCD using + * its XRES signal (active low) */ + BSP_LCD_Reset(); + + /* Check the connected monitor */ + read_id = LCD_IO_GetID(); + +#if defined(USE_LCD_HDMI) + if(read_id == ADV7533_ID) + { + return BSP_LCD_HDMIInitEx(HDMI_FORMAT_720_576); + } + else if(read_id != LCD_DSI_ID) + { + return LCD_ERROR; + } +#else + if(read_id != LCD_DSI_ID) + { + return LCD_ERROR; + } +#endif /* USE_LCD_HDMI */ + + /* Call first MSP Initialize only in case of first initialization + * This will set IP blocks LTDC, DSI and DMA2D + * - out of reset + * - clocked + * - NVIC IRQ related to IP blocks enabled + */ + BSP_LCD_MspInit(); + +/*************************DSI Initialization***********************************/ + + /* Base address of DSI Host/Wrapper registers to be set before calling De-Init */ + hdsi_eval.Instance = DSI; + + HAL_DSI_DeInit(&(hdsi_eval)); + + dsiPllInit.PLLNDIV = 100; + dsiPllInit.PLLIDF = DSI_PLL_IN_DIV5; + dsiPllInit.PLLODF = DSI_PLL_OUT_DIV1; + laneByteClk_kHz = 62500; /* 500 MHz / 8 = 62.5 MHz = 62500 kHz */ + + /* Set number of Lanes */ + hdsi_eval.Init.NumberOfLanes = DSI_TWO_DATA_LANES; + + /* TXEscapeCkdiv = f(LaneByteClk)/15.62 = 4 */ + hdsi_eval.Init.TXEscapeCkdiv = laneByteClk_kHz/15620; + + HAL_DSI_Init(&(hdsi_eval), &(dsiPllInit)); + /* Timing parameters for all Video modes + * Set Timing parameters of LTDC depending on its chosen orientation + */ + if(orientation == LCD_ORIENTATION_PORTRAIT) + { + lcd_x_size = OTM8009A_480X800_WIDTH; /* 480 */ + lcd_y_size = OTM8009A_480X800_HEIGHT; /* 800 */ + } + else + { + /* lcd_orientation == LCD_ORIENTATION_LANDSCAPE */ + lcd_x_size = OTM8009A_800X480_WIDTH; /* 800 */ + lcd_y_size = OTM8009A_800X480_HEIGHT; /* 480 */ + } + + HACT = lcd_x_size; + VACT = lcd_y_size; + + /* The following values are same for portrait and landscape orientations */ + VSA = OTM8009A_480X800_VSYNC; + VBP = OTM8009A_480X800_VBP; + VFP = OTM8009A_480X800_VFP; + HSA = OTM8009A_480X800_HSYNC; + HBP = OTM8009A_480X800_HBP; + HFP = OTM8009A_480X800_HFP; + + hdsivideo_handle.VirtualChannelID = LCD_OTM8009A_ID; + hdsivideo_handle.ColorCoding = LCD_DSI_PIXEL_DATA_FMT_RBG888; + hdsivideo_handle.VSPolarity = DSI_VSYNC_ACTIVE_HIGH; + hdsivideo_handle.HSPolarity = DSI_HSYNC_ACTIVE_HIGH; + hdsivideo_handle.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH; + hdsivideo_handle.Mode = DSI_VID_MODE_BURST; /* Mode Video burst ie : one LgP per line */ + hdsivideo_handle.NullPacketSize = 0xFFF; + hdsivideo_handle.NumberOfChunks = 0; + hdsivideo_handle.PacketSize = HACT; /* Value depending on display orientation choice portrait/landscape */ + hdsivideo_handle.HorizontalSyncActive = (HSA * laneByteClk_kHz)/LcdClock; + hdsivideo_handle.HorizontalBackPorch = (HBP * laneByteClk_kHz)/LcdClock; + hdsivideo_handle.HorizontalLine = ((HACT + HSA + HBP + HFP) * laneByteClk_kHz)/LcdClock; /* Value depending on display orientation choice portrait/landscape */ + hdsivideo_handle.VerticalSyncActive = VSA; + hdsivideo_handle.VerticalBackPorch = VBP; + hdsivideo_handle.VerticalFrontPorch = VFP; + hdsivideo_handle.VerticalActive = VACT; /* Value depending on display orientation choice portrait/landscape */ + + /* Enable or disable sending LP command while streaming is active in video mode */ + hdsivideo_handle.LPCommandEnable = DSI_LP_COMMAND_ENABLE; /* Enable sending commands in mode LP (Low Power) */ + + /* Largest packet size possible to transmit in LP mode in VSA, VBP, VFP regions */ + /* Only useful when sending LP packets is allowed while streaming is active in video mode */ + hdsivideo_handle.LPLargestPacketSize = 16; + + /* Largest packet size possible to transmit in LP mode in HFP region during VACT period */ + /* Only useful when sending LP packets is allowed while streaming is active in video mode */ + hdsivideo_handle.LPVACTLargestPacketSize = 0; + + /* Specify for each region of the video frame, if the transmission of command in LP mode is allowed in this region */ + /* while streaming is active in video mode */ + hdsivideo_handle.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE; /* Allow sending LP commands during HFP period */ + hdsivideo_handle.LPHorizontalBackPorchEnable = DSI_LP_HBP_ENABLE; /* Allow sending LP commands during HBP period */ + hdsivideo_handle.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE; /* Allow sending LP commands during VACT period */ + hdsivideo_handle.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE; /* Allow sending LP commands during VFP period */ + hdsivideo_handle.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE; /* Allow sending LP commands during VBP period */ + hdsivideo_handle.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE; /* Allow sending LP commands during VSync = VSA period */ + + /* Configure DSI Video mode timings with settings set above */ + HAL_DSI_ConfigVideoMode(&(hdsi_eval), &(hdsivideo_handle)); + +/*************************End DSI Initialization*******************************/ + + +/************************LTDC Initialization***********************************/ + + /* Timing Configuration */ + hltdc_eval.Init.HorizontalSync = (HSA - 1); + hltdc_eval.Init.AccumulatedHBP = (HSA + HBP - 1); + hltdc_eval.Init.AccumulatedActiveW = (lcd_x_size + HSA + HBP - 1); + hltdc_eval.Init.TotalWidth = (lcd_x_size + HSA + HBP + HFP - 1); + + /* Initialize the LCD pixel width and pixel height */ + hltdc_eval.LayerCfg->ImageWidth = lcd_x_size; + hltdc_eval.LayerCfg->ImageHeight = lcd_y_size; + + /** LCD clock configuration + * Note: The following values should not be changed as the PLLSAI is also used + * to clock the USB FS + * PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz + * PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 384 Mhz + * PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 384 MHz / 7 = 54.85 MHz + * LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_2 = 54.85 MHz / 2 = 27.429 MHz + */ + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; + PeriphClkInitStruct.PLLSAI.PLLSAIN = 384; + PeriphClkInitStruct.PLLSAI.PLLSAIR = 7; + PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_2; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); + + /* Background value */ + hltdc_eval.Init.Backcolor.Blue = 0; + hltdc_eval.Init.Backcolor.Green = 0; + hltdc_eval.Init.Backcolor.Red = 0; + hltdc_eval.Init.PCPolarity = LTDC_PCPOLARITY_IPC; + hltdc_eval.Instance = LTDC; + + /* Get LTDC Configuration from DSI Configuration */ + HAL_LTDC_StructInitFromVideoConfig(&(hltdc_eval), &(hdsivideo_handle)); + + /* Initialize the LTDC */ + HAL_LTDC_Init(&hltdc_eval); + + /* Enable the DSI host and wrapper after the LTDC initialization + To avoid any synchronization issue, the DSI shall be started after enabling the LTDC */ + HAL_DSI_Start(&(hdsi_eval)); + +#if !defined(DATA_IN_ExtSDRAM) + /* Initialize the SDRAM */ + BSP_SDRAM_Init(); +#endif /* DATA_IN_ExtSDRAM */ + + /* Initialize the font */ + BSP_LCD_SetFont(&LCD_DEFAULT_FONT); + +/************************End LTDC Initialization*******************************/ + + +/***********************OTM8009A Initialization********************************/ + + /* Initialize the OTM8009A LCD Display IC Driver (KoD LCD IC Driver) + * depending on configuration set in 'hdsivideo_handle'. + */ + OTM8009A_Init(OTM8009A_FORMAT_RGB888, orientation); + +/***********************End OTM8009A Initialization****************************/ + + return LCD_OK; +} + +#if defined(USE_LCD_HDMI) +/** + * @brief Initializes the DSI for HDMI monitor. + * The ititialization is done as below: + * - DSI PLL ititialization + * - DSI ititialization + * - LTDC ititialization + * - DSI-HDMI ADV7533 adapter device ititialization + * @param format : HDMI format could be HDMI_FORMAT_720_480 or HDMI_FORMAT_720_576 + * @retval LCD state + */ +uint8_t BSP_LCD_HDMIInitEx(uint8_t format) +{ + /************************ADV7533 Initialization******************************/ + + /* Initialize the ADV7533 HDMI Bridge + depending on configuration set in 'hdsivideo_handle'. */ + adv7533ConfigTypeDef adv7533_config; + + adv7533_config.DSI_LANES = 2; + adv7533_config.HACT = HDMI_Format[format].HACT; + adv7533_config.HSYNC = HDMI_Format[format].HSYNC; + adv7533_config.HBP = HDMI_Format[format].HBP; + adv7533_config.HFP = HDMI_Format[format].HFP; + adv7533_config.VACT = HDMI_Format[format].VACT; + adv7533_config.VSYNC = HDMI_Format[format].VSYNC; + adv7533_config.VBP = HDMI_Format[format].VBP; + adv7533_config.VFP = HDMI_Format[format].VFP; + + ADV7533_Init(); + ADV7533_Configure(&adv7533_config); + ADV7533_PowerOn(); + +/************************ Update hdmi_x_size and hdmi_y_size *****************/ + lcd_x_size = HDMI_Format[format].HACT; + lcd_y_size = HDMI_Format[format].VACT; + +/***********************End ADV7533 Initialization****************************/ + + DSI_PLLInitTypeDef dsiPllInit; + DSI_PHY_TimerTypeDef dsiPhyInit; + static RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + + /* Call first MSP Initialize only in case of first initialization + * This will set IP blocks LTDC and DSI + * - out of reset + * - clocked + * - NVIC IRQ related to IP blocks enabled + */ + BSP_LCD_MspInit(); + +/*************************DSI Initialization***********************************/ + + /* Base address of DSI Host/Wrapper registers to be set before calling De-Init */ + hdsi_eval.Instance = DSI; + + HAL_DSI_DeInit(&(hdsi_eval)); + + /* Configure the DSI PLL */ + dsiPllInit.PLLNDIV = HDMI_PLLConfig[format].NDIV; + dsiPllInit.PLLIDF = HDMI_PLLConfig[format].IDF; + dsiPllInit.PLLODF = HDMI_PLLConfig[format].ODF; + + /* Set number of Lanes */ + hdsi_eval.Init.NumberOfLanes = DSI_TWO_DATA_LANES; + /* Set the TX escape clock division ratio */ + hdsi_eval.Init.TXEscapeCkdiv = HDMI_PLLConfig[format].TXEscapeCkdiv; + /* Disable the automatic clock lane control (the ADV7533 must be clocked) */ + hdsi_eval.Init.AutomaticClockLaneControl = DSI_AUTO_CLK_LANE_CTRL_DISABLE; + + /* Init the DSI */ + HAL_DSI_Init(&hdsi_eval, &dsiPllInit); + + /* Configure the D-PHY Timings */ + dsiPhyInit.ClockLaneHS2LPTime = 0x14; + dsiPhyInit.ClockLaneLP2HSTime = 0x14; + dsiPhyInit.DataLaneHS2LPTime = 0x0A; + dsiPhyInit.DataLaneLP2HSTime = 0x0A; + dsiPhyInit.DataLaneMaxReadTime = 0x00; + dsiPhyInit.StopWaitTime = 0x0; + HAL_DSI_ConfigPhyTimer(&hdsi_eval, &dsiPhyInit); + + /* Virutal channel used by the ADV7533 */ + hdsivideo_handle.VirtualChannelID = HDMI_ADV7533_ID; + + /* Timing parameters for Video modes + Set Timing parameters of DSI depending on its chosen format */ + hdsivideo_handle.ColorCoding = HDMI_Format[format].RGB_CODING; + hdsivideo_handle.LooselyPacked = DSI_LOOSELY_PACKED_DISABLE; + hdsivideo_handle.VSPolarity = DSI_VSYNC_ACTIVE_LOW; + hdsivideo_handle.HSPolarity = DSI_HSYNC_ACTIVE_LOW; + hdsivideo_handle.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH; + hdsivideo_handle.Mode = DSI_VID_MODE_NB_PULSES; + hdsivideo_handle.NullPacketSize = HDMI_DSIPacket[format].NullPacketSize; + hdsivideo_handle.NumberOfChunks = HDMI_DSIPacket[format].NumberOfChunks; + hdsivideo_handle.PacketSize = HDMI_DSIPacket[format].PacketSize; + hdsivideo_handle.HorizontalSyncActive = HDMI_Format[format].HSYNC*HDMI_PLLConfig[format].LaneByteClock/HDMI_PLLConfig[format].PCLK; + hdsivideo_handle.HorizontalBackPorch = HDMI_Format[format].HBP*HDMI_PLLConfig[format].LaneByteClock/HDMI_PLLConfig[format].PCLK; + hdsivideo_handle.HorizontalLine = (HDMI_Format[format].HACT + HDMI_Format[format].HSYNC + HDMI_Format[format].HBP + HDMI_Format[format].HFP)*HDMI_PLLConfig[format].LaneByteClock/HDMI_PLLConfig[format].PCLK; + hdsivideo_handle.VerticalSyncActive = HDMI_Format[format].VSYNC; + hdsivideo_handle.VerticalBackPorch = HDMI_Format[format].VBP; + hdsivideo_handle.VerticalFrontPorch = HDMI_Format[format].VFP; + hdsivideo_handle.VerticalActive = HDMI_Format[format].VACT; + + /* Enable or disable sending LP command while streaming is active in video mode */ + hdsivideo_handle.LPCommandEnable = DSI_LP_COMMAND_DISABLE; /* Enable sending commands in mode LP (Low Power) */ + + /* Largest packet size possible to transmit in LP mode in VSA, VBP, VFP regions */ + /* Only useful when sending LP packets is allowed while streaming is active in video mode */ + hdsivideo_handle.LPLargestPacketSize = 4; + + /* Largest packet size possible to transmit in LP mode in HFP region during VACT period */ + /* Only useful when sending LP packets is allowed while streaming is active in video mode */ + hdsivideo_handle.LPVACTLargestPacketSize = 4; + + /* Specify for each region, if the going in LP mode is allowed */ + /* while streaming is active in video mode */ + hdsivideo_handle.LPHorizontalFrontPorchEnable = DSI_LP_HFP_DISABLE; + hdsivideo_handle.LPHorizontalBackPorchEnable = DSI_LP_HBP_DISABLE; + hdsivideo_handle.LPVerticalActiveEnable = DSI_LP_VACT_DISABLE; + hdsivideo_handle.LPVerticalFrontPorchEnable = DSI_LP_VFP_DISABLE; + hdsivideo_handle.LPVerticalBackPorchEnable = DSI_LP_VBP_DISABLE; + hdsivideo_handle.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_DISABLE; + + /* No acknoledge at the end of a frame */ + hdsivideo_handle.FrameBTAAcknowledgeEnable = DSI_FBTAA_DISABLE; + + /* Configure DSI Video mode timings with settings set above */ + HAL_DSI_ConfigVideoMode(&hdsi_eval, &hdsivideo_handle); + + /* Enable the DSI host and wrapper : but LTDC is not started yet at this stage */ + HAL_DSI_Start(&hdsi_eval); + +/*************************End DSI Initialization*******************************/ + + +/************************LTDC Initialization***********************************/ + + /* LTDC clock configuration */ + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; + PeriphClkInitStruct.PLLSAI.PLLSAIN = HDMI_PLLConfig[format].PLLSAIN; + PeriphClkInitStruct.PLLSAI.PLLSAIR = HDMI_PLLConfig[format].PLLSAIR; + PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_2; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); + + /* Base address of LTDC registers to be set before calling De-Init */ + hltdc_eval.Instance = LTDC; + + HAL_LTDC_DeInit(&(hltdc_eval)); + + /* Timing Configuration */ + hltdc_eval.Init.HorizontalSync = (HDMI_Format[format].HSYNC - 1); + hltdc_eval.Init.AccumulatedHBP = (HDMI_Format[format].HSYNC + HDMI_Format[format].HBP - 1); + hltdc_eval.Init.AccumulatedActiveW = (HDMI_Format[format].HACT + HDMI_Format[format].HSYNC + HDMI_Format[format].HBP - 1); + hltdc_eval.Init.TotalWidth = (HDMI_Format[format].HACT + HDMI_Format[format].HSYNC + HDMI_Format[format].HBP + HDMI_Format[format].HFP - 1); + hltdc_eval.Init.VerticalSync = (HDMI_Format[format].VSYNC - 1); + hltdc_eval.Init.AccumulatedVBP = (HDMI_Format[format].VSYNC + HDMI_Format[format].VBP - 1); + hltdc_eval.Init.AccumulatedActiveH = (HDMI_Format[format].VACT + HDMI_Format[format].VSYNC + HDMI_Format[format].VBP - 1); + hltdc_eval.Init.TotalHeigh = (HDMI_Format[format].VACT + HDMI_Format[format].VSYNC + HDMI_Format[format].VBP + HDMI_Format[format].VFP - 1); + + /* background value */ + hltdc_eval.Init.Backcolor.Blue = 0x00; + hltdc_eval.Init.Backcolor.Green = 0xFF; + hltdc_eval.Init.Backcolor.Red = 0xFF; + + /* Polarity */ + hltdc_eval.Init.HSPolarity = LTDC_HSPOLARITY_AL; + hltdc_eval.Init.VSPolarity = LTDC_VSPOLARITY_AL; + hltdc_eval.Init.DEPolarity = LTDC_DEPOLARITY_AL; + hltdc_eval.Init.PCPolarity = LTDC_PCPOLARITY_IPC; + + /* Initialize & Start the LTDC */ + HAL_LTDC_Init(&hltdc_eval); + +#if !defined(DATA_IN_ExtSDRAM) + /* Initialize the SDRAM */ + BSP_SDRAM_Init(); +#endif /* DATA_IN_ExtSDRAM */ + + /* Initialize the font */ + BSP_LCD_SetFont(&LCD_DEFAULT_FONT); +/************************End LTDC Initialization*******************************/ + + return LCD_OK; +} +#endif /* USE_LCD_HDMI */ + +/** + * @brief BSP LCD Reset + * Hw reset the LCD DSI activating its XRES signal (active low for some time) + * and desactivating it later. + */ +void BSP_LCD_Reset(void) +{ + GPIO_InitTypeDef gpio_init_structure; + + __HAL_RCC_GPIOK_CLK_ENABLE(); + + /* Configure the GPIO on PK7 */ + gpio_init_structure.Pin = GPIO_PIN_7; + gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + + HAL_GPIO_Init(GPIOK, &gpio_init_structure); + + /* Activate XRES active low */ + HAL_GPIO_WritePin(GPIOK, GPIO_PIN_7, GPIO_PIN_RESET); + + HAL_Delay(20); /* wait 20 ms */ + + /* Desactivate XRES */ + HAL_GPIO_WritePin(GPIOK, GPIO_PIN_7, GPIO_PIN_SET); + + /* Wait for 10ms after releasing XRES before sending commands */ + HAL_Delay(10); +} + +/** + * @brief Gets the LCD X size. + * @retval Used LCD X size + */ +uint32_t BSP_LCD_GetXSize(void) +{ + return (lcd_x_size); +} + +/** + * @brief Gets the LCD Y size. + * @retval Used LCD Y size + */ +uint32_t BSP_LCD_GetYSize(void) +{ + return (lcd_y_size); +} + +/** + * @brief Set the LCD X size. + * @param imageWidthPixels : uint32_t image width in pixels unit + * @retval None + */ +void BSP_LCD_SetXSize(uint32_t imageWidthPixels) +{ + hltdc_eval.LayerCfg[ActiveLayer].ImageWidth = imageWidthPixels; +} + +/** + * @brief Set the LCD Y size. + * @param imageHeightPixels : uint32_t image height in lines unit + */ +void BSP_LCD_SetYSize(uint32_t imageHeightPixels) +{ + hltdc_eval.LayerCfg[ActiveLayer].ImageHeight = imageHeightPixels; +} + + +/** + * @brief Initializes the LCD layers. + * @param LayerIndex: Layer foreground or background + * @param FB_Address: Layer frame buffer + * @retval None + */ +void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) +{ + LCD_LayerCfgTypeDef Layercfg; + + /* Layer Init */ + Layercfg.WindowX0 = 0; + Layercfg.WindowX1 = BSP_LCD_GetXSize(); + Layercfg.WindowY0 = 0; + Layercfg.WindowY1 = BSP_LCD_GetYSize(); + Layercfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888; + Layercfg.FBStartAdress = FB_Address; + Layercfg.Alpha = 255; + Layercfg.Alpha0 = 0; + Layercfg.Backcolor.Blue = 0; + Layercfg.Backcolor.Green = 0; + Layercfg.Backcolor.Red = 0; + Layercfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; + Layercfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; + Layercfg.ImageWidth = BSP_LCD_GetXSize(); + Layercfg.ImageHeight = BSP_LCD_GetYSize(); + + HAL_LTDC_ConfigLayer(&hltdc_eval, &Layercfg, LayerIndex); + + DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE; + DrawProp[LayerIndex].pFont = &Font24; + DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK; +} + + +/** + * @brief Selects the LCD Layer. + * @param LayerIndex: Layer foreground or background + */ +void BSP_LCD_SelectLayer(uint32_t LayerIndex) +{ + ActiveLayer = LayerIndex; +} + +/** + * @brief Sets an LCD Layer visible + * @param LayerIndex: Visible Layer + * @param State: New state of the specified layer + * This parameter can be one of the following values: + * @arg ENABLE + * @arg DISABLE + */ +void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState State) +{ + if(State == ENABLE) + { + __HAL_LTDC_LAYER_ENABLE(&(hltdc_eval), LayerIndex); + } + else + { + __HAL_LTDC_LAYER_DISABLE(&(hltdc_eval), LayerIndex); + } + __HAL_LTDC_RELOAD_CONFIG(&(hltdc_eval)); + +} + +/** + * @brief Configures the transparency. + * @param LayerIndex: Layer foreground or background. + * @param Transparency: Transparency + * This parameter must be a number between Min_Data = 0x00 and Max_Data = 0xFF + */ +void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency) +{ + + HAL_LTDC_SetAlpha(&(hltdc_eval), Transparency, LayerIndex); + +} + +/** + * @brief Sets an LCD layer frame buffer address. + * @param LayerIndex: Layer foreground or background + * @param Address: New LCD frame buffer value + */ +void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address) +{ + + HAL_LTDC_SetAddress(&(hltdc_eval), Address, LayerIndex); + +} + +/** + * @brief Sets display window. + * @param LayerIndex: Layer index + * @param Xpos: LCD X position + * @param Ypos: LCD Y position + * @param Width: LCD window width + * @param Height: LCD window height + */ +void BSP_LCD_SetLayerWindow(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Reconfigure the layer size */ + HAL_LTDC_SetWindowSize(&(hltdc_eval), Width, Height, LayerIndex); + + /* Reconfigure the layer position */ + HAL_LTDC_SetWindowPosition(&(hltdc_eval), Xpos, Ypos, LayerIndex); + +} + +/** + * @brief Configures and sets the color keying. + * @param LayerIndex: Layer foreground or background + * @param RGBValue: Color reference + */ +void BSP_LCD_SetColorKeying(uint32_t LayerIndex, uint32_t RGBValue) +{ + /* Configure and Enable the color Keying for LCD Layer */ + HAL_LTDC_ConfigColorKeying(&(hltdc_eval), RGBValue, LayerIndex); + HAL_LTDC_EnableColorKeying(&(hltdc_eval), LayerIndex); +} + +/** + * @brief Disables the color keying. + * @param LayerIndex: Layer foreground or background + */ +void BSP_LCD_ResetColorKeying(uint32_t LayerIndex) +{ + /* Disable the color Keying for LCD Layer */ + HAL_LTDC_DisableColorKeying(&(hltdc_eval), LayerIndex); +} + +/** + * @brief Sets the LCD text color. + * @param Color: Text color code ARGB(8-8-8-8) + */ +void BSP_LCD_SetTextColor(uint32_t Color) +{ + DrawProp[ActiveLayer].TextColor = Color; +} + +/** + * @brief Gets the LCD text color. + * @retval Used text color. + */ +uint32_t BSP_LCD_GetTextColor(void) +{ + return DrawProp[ActiveLayer].TextColor; +} + +/** + * @brief Sets the LCD background color. + * @param Color: Layer background color code ARGB(8-8-8-8) + */ +void BSP_LCD_SetBackColor(uint32_t Color) +{ + DrawProp[ActiveLayer].BackColor = Color; +} + +/** + * @brief Gets the LCD background color. + * @retval Used background color + */ +uint32_t BSP_LCD_GetBackColor(void) +{ + return DrawProp[ActiveLayer].BackColor; +} + +/** + * @brief Sets the LCD text font. + * @param fonts: Layer font to be used + */ +void BSP_LCD_SetFont(sFONT *fonts) +{ + DrawProp[ActiveLayer].pFont = fonts; +} + +/** + * @brief Gets the LCD text font. + * @retval Used layer font + */ +sFONT *BSP_LCD_GetFont(void) +{ + return DrawProp[ActiveLayer].pFont; +} + +/** + * @brief Reads an LCD pixel. + * @param Xpos: X position + * @param Ypos: Y position + * @retval RGB pixel color + */ +uint32_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos) +{ + uint32_t ret = 0; + + if(hltdc_eval.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB8888) + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint32_t*) (hltdc_eval.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + else if(hltdc_eval.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB888) + { + /* Read data value from SDRAM memory */ + ret = (*(__IO uint32_t*) (hltdc_eval.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))) & 0x00FFFFFF); + } + else if((hltdc_eval.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565) || \ + (hltdc_eval.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_ARGB4444) || \ + (hltdc_eval.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_AL88)) + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint16_t*) (hltdc_eval.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + else + { + /* Read data value from SDRAM memory */ + ret = *(__IO uint8_t*) (hltdc_eval.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))); + } + + return ret; +} + +/** + * @brief Clears the whole currently active layer of LTDC. + * @param Color: Color of the background + */ +void BSP_LCD_Clear(uint32_t Color) +{ + /* Clear the LCD */ + LL_FillBuffer(ActiveLayer, (uint32_t *)(hltdc_eval.LayerCfg[ActiveLayer].FBStartAdress), BSP_LCD_GetXSize(), BSP_LCD_GetYSize(), 0, Color); +} + +/** + * @brief Clears the selected line in currently active layer. + * @param Line: Line to be cleared + */ +void BSP_LCD_ClearStringLine(uint32_t Line) +{ + uint32_t color_backup = DrawProp[ActiveLayer].TextColor; + DrawProp[ActiveLayer].TextColor = DrawProp[ActiveLayer].BackColor; + + /* Draw rectangle with background color */ + BSP_LCD_FillRect(0, (Line * DrawProp[ActiveLayer].pFont->Height), BSP_LCD_GetXSize(), DrawProp[ActiveLayer].pFont->Height); + + DrawProp[ActiveLayer].TextColor = color_backup; + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Displays one character in currently active layer. + * @param Xpos: Start column address + * @param Ypos: Line where to display the character shape. + * @param Ascii: Character ascii code + * This parameter must be a number between Min_Data = 0x20 and Max_Data = 0x7E + */ +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii) +{ + DrawChar(Xpos, Ypos, &DrawProp[ActiveLayer].pFont->table[(Ascii-' ') *\ + DrawProp[ActiveLayer].pFont->Height * ((DrawProp[ActiveLayer].pFont->Width + 7) / 8)]); +} + +/** + * @brief Displays characters in currently active layer. + * @param Xpos: X position (in pixel) + * @param Ypos: Y position (in pixel) + * @param Text: Pointer to string to display on LCD + * @param Mode: Display mode + * This parameter can be one of the following values: + * @arg CENTER_MODE + * @arg RIGHT_MODE + * @arg LEFT_MODE + */ +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode) +{ + uint16_t refcolumn = 1, i = 0; + uint32_t size = 0, xsize = 0; + uint8_t *ptr = Text; + + /* Get the text size */ + while (*ptr++) size ++ ; + + /* Characters number per line */ + xsize = (BSP_LCD_GetXSize()/DrawProp[ActiveLayer].pFont->Width); + + switch (Mode) + { + case CENTER_MODE: + { + refcolumn = Xpos + ((xsize - size)* DrawProp[ActiveLayer].pFont->Width) / 2; + break; + } + case LEFT_MODE: + { + refcolumn = Xpos; + break; + } + case RIGHT_MODE: + { + refcolumn = - Xpos + ((xsize - size)*DrawProp[ActiveLayer].pFont->Width); + break; + } + default: + { + refcolumn = Xpos; + break; + } + } + + /* Check that the Start column is located in the screen */ + if ((refcolumn < 1) || (refcolumn >= 0x8000)) + { + refcolumn = 1; + } + + /* Send the string character by character on LCD */ + while ((*Text != 0) & (((BSP_LCD_GetXSize() - (i*DrawProp[ActiveLayer].pFont->Width)) & 0xFFFF) >= DrawProp[ActiveLayer].pFont->Width)) + { + /* Display one character on LCD */ + BSP_LCD_DisplayChar(refcolumn, Ypos, *Text); + /* Decrement the column position by 16 */ + refcolumn += DrawProp[ActiveLayer].pFont->Width; + + /* Point on the next character */ + Text++; + i++; + } + +} + +/** + * @brief Displays a maximum of 60 characters on the LCD. + * @param Line: Line where to display the character shape + * @param ptr: Pointer to string to display on LCD + */ +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr) +{ + BSP_LCD_DisplayStringAt(0, LINE(Line), ptr, LEFT_MODE); +} + +/** + * @brief Draws an horizontal line in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + */ +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t Xaddress = 0; + + /* Get the line address */ + Xaddress = (hltdc_eval.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + + /* Write line */ + LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, Length, 1, 0, DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws a vertical line in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param Length: Line length + */ +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length) +{ + uint32_t Xaddress = 0; + + /* Get the line address */ + Xaddress = (hltdc_eval.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + + /* Write line */ + LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, 1, Length, (BSP_LCD_GetXSize() - 1), DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws an uni-line (between two points) in currently active layer. + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + */ +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + numadd = deltay; + numpixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + numadd = deltax; + numpixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= numpixels; curpixel++) + { + BSP_LCD_DrawPixel(x, y, DrawProp[ActiveLayer].TextColor); /* Draw the current pixel */ + num += numadd; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Draws a rectangle in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + */ +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + /* Draw horizontal lines */ + BSP_LCD_DrawHLine(Xpos, Ypos, Width); + BSP_LCD_DrawHLine(Xpos, (Ypos+ Height), Width); + + /* Draw vertical lines */ + BSP_LCD_DrawVLine(Xpos, Ypos, Height); + BSP_LCD_DrawVLine((Xpos + Width), Ypos, Height); +} + +/** + * @brief Draws a circle in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + */ +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t D; /* Decision Variable */ + uint32_t CurX; /* Current X Value */ + uint32_t CurY; /* Current Y Value */ + + D = 3 - (Radius << 1); + CurX = 0; + CurY = Radius; + + while (CurX <= CurY) + { + BSP_LCD_DrawPixel((Xpos + CurX), (Ypos - CurY), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - CurX), (Ypos - CurY), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + CurY), (Ypos - CurX), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - CurY), (Ypos - CurX), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + CurX), (Ypos + CurY), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - CurX), (Ypos + CurY), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos + CurY), (Ypos + CurX), DrawProp[ActiveLayer].TextColor); + + BSP_LCD_DrawPixel((Xpos - CurY), (Ypos + CurX), DrawProp[ActiveLayer].TextColor); + + if (D < 0) + { + D += (CurX << 2) + 6; + } + else + { + D += ((CurX - CurY) << 2) + 10; + CurY--; + } + CurX++; + } +} + +/** + * @brief Draws an poly-line (between many points) in currently active layer. + * @param Points: Pointer to the points array + * @param PointCount: Number of points + */ +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t X = 0, Y = 0; + + if(PointCount < 2) + { + return; + } + + BSP_LCD_DrawLine(Points->X, Points->Y, (Points+PointCount-1)->X, (Points+PointCount-1)->Y); + + while(--PointCount) + { + X = Points->X; + Y = Points->Y; + Points++; + BSP_LCD_DrawLine(X, Y, Points->X, Points->Y); + } +} + +/** + * @brief Draws an ellipse on LCD in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + */ +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float K = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + K = (float)(rad2/rad1); + + do { + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/K)), (Ypos+y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/K)), (Ypos+y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos+(uint16_t)(x/K)), (Ypos-y), DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawPixel((Xpos-(uint16_t)(x/K)), (Ypos-y), DrawProp[ActiveLayer].TextColor); + + e2 = err; + if (e2 <= x) { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Draws a bitmap picture loaded in the internal Flash (32 bpp) in currently active layer. + * @param Xpos: Bmp X position in the LCD + * @param Ypos: Bmp Y position in the LCD + * @param pbmp: Pointer to Bmp picture address in the internal Flash + */ +void BSP_LCD_DrawBitmap(uint32_t Xpos, uint32_t Ypos, uint8_t *pbmp) +{ + uint32_t index = 0, width = 0, height = 0, bit_pixel = 0; + uint32_t Address; + uint32_t InputColorMode = 0; + + /* Get bitmap data address offset */ + index = pbmp[10] + (pbmp[11] << 8) + (pbmp[12] << 16) + (pbmp[13] << 24); + + /* Read bitmap width */ + width = pbmp[18] + (pbmp[19] << 8) + (pbmp[20] << 16) + (pbmp[21] << 24); + + /* Read bitmap height */ + height = pbmp[22] + (pbmp[23] << 8) + (pbmp[24] << 16) + (pbmp[25] << 24); + + /* Read bit/pixel */ + bit_pixel = pbmp[28] + (pbmp[29] << 8); + + /* Set the address */ + Address = hltdc_eval.LayerCfg[ActiveLayer].FBStartAdress + (((BSP_LCD_GetXSize()*Ypos) + Xpos)*(4)); + + /* Get the layer pixel format */ + if ((bit_pixel/8) == 4) + { + InputColorMode = DMA2D_INPUT_ARGB8888; + } + else if ((bit_pixel/8) == 2) + { + InputColorMode = DMA2D_INPUT_RGB565; + } + else + { + InputColorMode = DMA2D_INPUT_RGB888; + } + + /* Bypass the bitmap header */ + pbmp += (index + (width * (height - 1) * (bit_pixel/8))); + + /* Convert picture to ARGB8888 pixel format */ + for(index=0; index < height; index++) + { + /* Pixel format conversion */ + LL_ConvertLineToARGB8888((uint32_t *)pbmp, (uint32_t *)Address, width, InputColorMode); + + /* Increment the source and destination buffers */ + Address+= (BSP_LCD_GetXSize()*4); + pbmp -= width*(bit_pixel/8); + } +} + +/** + * @brief Draws a full rectangle in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param Width: Rectangle width + * @param Height: Rectangle height + */ +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height) +{ + uint32_t Xaddress = 0; + + /* Set the text color */ + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + + /* Get the rectangle start address */ + Xaddress = (hltdc_eval.LayerCfg[ActiveLayer].FBStartAdress) + 4*(BSP_LCD_GetXSize()*Ypos + Xpos); + + /* Fill the rectangle */ + LL_FillBuffer(ActiveLayer, (uint32_t *)Xaddress, Width, Height, (BSP_LCD_GetXSize() - Width), DrawProp[ActiveLayer].TextColor); +} + +/** + * @brief Draws a full circle in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param Radius: Circle radius + */ +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius) +{ + int32_t D; /* Decision Variable */ + uint32_t CurX; /* Current X Value */ + uint32_t CurY; /* Current Y Value */ + + D = 3 - (Radius << 1); + + CurX = 0; + CurY = Radius; + + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + + while (CurX <= CurY) + { + if(CurY > 0) + { + BSP_LCD_DrawHLine(Xpos - CurY, Ypos + CurX, 2*CurY); + BSP_LCD_DrawHLine(Xpos - CurY, Ypos - CurX, 2*CurY); + } + + if(CurX > 0) + { + BSP_LCD_DrawHLine(Xpos - CurX, Ypos - CurY, 2*CurX); + BSP_LCD_DrawHLine(Xpos - CurX, Ypos + CurY, 2*CurX); + } + if (D < 0) + { + D += (CurX << 2) + 6; + } + else + { + D += ((CurX - CurY) << 2) + 10; + CurY--; + } + CurX++; + } + + BSP_LCD_SetTextColor(DrawProp[ActiveLayer].TextColor); + BSP_LCD_DrawCircle(Xpos, Ypos, Radius); +} + +/** + * @brief Draws a full poly-line (between many points) in currently active layer. + * @param Points: Pointer to the points array + * @param PointCount: Number of points + */ +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount) +{ + int16_t X = 0, Y = 0, X2 = 0, Y2 = 0, X_center = 0, Y_center = 0, X_first = 0, Y_first = 0, pixelX = 0, pixelY = 0, counter = 0; + uint16_t IMAGE_LEFT = 0, IMAGE_RIGHT = 0, IMAGE_TOP = 0, IMAGE_BOTTOM = 0; + + IMAGE_LEFT = IMAGE_RIGHT = Points->X; + IMAGE_TOP= IMAGE_BOTTOM = Points->Y; + + for(counter = 1; counter < PointCount; counter++) + { + pixelX = POLY_X(counter); + if(pixelX < IMAGE_LEFT) + { + IMAGE_LEFT = pixelX; + } + if(pixelX > IMAGE_RIGHT) + { + IMAGE_RIGHT = pixelX; + } + + pixelY = POLY_Y(counter); + if(pixelY < IMAGE_TOP) + { + IMAGE_TOP = pixelY; + } + if(pixelY > IMAGE_BOTTOM) + { + IMAGE_BOTTOM = pixelY; + } + } + + if(PointCount < 2) + { + return; + } + + X_center = (IMAGE_LEFT + IMAGE_RIGHT)/2; + Y_center = (IMAGE_BOTTOM + IMAGE_TOP)/2; + + X_first = Points->X; + Y_first = Points->Y; + + while(--PointCount) + { + X = Points->X; + Y = Points->Y; + Points++; + X2 = Points->X; + Y2 = Points->Y; + + FillTriangle(X, X2, X_center, Y, Y2, Y_center); + FillTriangle(X, X_center, X2, Y, Y_center, Y2); + FillTriangle(X_center, X2, X, Y_center, Y2, Y); + } + + FillTriangle(X_first, X2, X_center, Y_first, Y2, Y_center); + FillTriangle(X_first, X_center, X2, Y_first, Y_center, Y2); + FillTriangle(X_center, X2, X_first, Y_center, Y2, Y_first); +} + +/** + * @brief Draws a full ellipse in currently active layer. + * @param Xpos: X position + * @param Ypos: Y position + * @param XRadius: Ellipse X radius + * @param YRadius: Ellipse Y radius + */ +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius) +{ + int x = 0, y = -YRadius, err = 2-2*XRadius, e2; + float K = 0, rad1 = 0, rad2 = 0; + + rad1 = XRadius; + rad2 = YRadius; + + K = (float)(rad2/rad1); + + do + { + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/K)), (Ypos+y), (2*(uint16_t)(x/K) + 1)); + BSP_LCD_DrawHLine((Xpos-(uint16_t)(x/K)), (Ypos-y), (2*(uint16_t)(x/K) + 1)); + + e2 = err; + if (e2 <= x) + { + err += ++x*2+1; + if (-y == x && e2 <= y) e2 = 0; + } + if (e2 > y) err += ++y*2+1; + } + while (y <= 0); +} + +/** + * @brief Switch back on the display if was switched off by previous call of BSP_LCD_DisplayOff(). + * Exit DSI ULPM mode if was allowed and configured in Dsi Configuration. + */ +void BSP_LCD_DisplayOn(void) +{ +#if defined(USE_LCD_HDMI) + if(ADV7533_ID == adv7533_drv.ReadID(ADV7533_CEC_DSI_I2C_ADDR)) + { + return ; /* Not supported for HDMI display */ + } + else +#endif /* USE_LCD_HDMI */ + { + + /* Send Display on DCS command to display */ + HAL_DSI_ShortWrite(&(hdsi_eval), + hdsivideo_handle.VirtualChannelID, + DSI_DCS_SHORT_PKT_WRITE_P1, + OTM8009A_CMD_DISPON, + 0x00); + } + +} + +/** + * @brief Switch Off the display. + * Enter DSI ULPM mode if was allowed and configured in Dsi Configuration. + */ +void BSP_LCD_DisplayOff(void) +{ +#if defined(USE_LCD_HDMI) + if(ADV7533_ID == adv7533_drv.ReadID(ADV7533_CEC_DSI_I2C_ADDR)) + { + return ; /* Not supported for HDMI yet */ + } + else +#endif /* USE_LCD_HDMI */ + { + /* Send Display off DCS Command to display */ + HAL_DSI_ShortWrite(&(hdsi_eval), + hdsivideo_handle.VirtualChannelID, + DSI_DCS_SHORT_PKT_WRITE_P1, + OTM8009A_CMD_DISPOFF, + 0x00); + } + +} + +/** + * @brief Set the brightness value + * @param BrightnessValue: [00: Min (black), 100 Max] + */ +void BSP_LCD_SetBrightness(uint8_t BrightnessValue) +{ +#if defined(USE_LCD_HDMI) + if(ADV7533_ID == adv7533_drv.ReadID(ADV7533_CEC_DSI_I2C_ADDR)) + { + return ; /* Not supported for HDMI display */ + } + else +#endif /* USE_LCD_HDMI */ + { + /* Send Display on DCS command to display */ + HAL_DSI_ShortWrite(&hdsi_eval, + LCD_OTM8009A_ID, + DSI_DCS_SHORT_PKT_WRITE_P1, + OTM8009A_CMD_WRDISBV, (uint16_t)(BrightnessValue * 255)/100); + } + +} + +/** + * @brief DCS or Generic short/long write command + * @param NbrParams: Number of parameters. It indicates the write command mode: + * If inferior to 2, a long write command is performed else short. + * @param pParams: Pointer to parameter values table. + * @retval HAL status + */ +void DSI_IO_WriteCmd(uint32_t NbrParams, uint8_t *pParams) +{ + if(NbrParams <= 1) + { + HAL_DSI_ShortWrite(&hdsi_eval, LCD_OTM8009A_ID, DSI_DCS_SHORT_PKT_WRITE_P1, pParams[0], pParams[1]); + } + else + { + HAL_DSI_LongWrite(&hdsi_eval, LCD_OTM8009A_ID, DSI_DCS_LONG_PKT_WRITE, NbrParams, pParams[NbrParams], pParams); + } +} + +/** + * @brief Returns the ID of connected screen by checking the HDMI + * (adv7533 component) ID or LCD DSI (via TS ID) ID. + * @retval LCD ID + */ +static uint16_t LCD_IO_GetID(void) +{ +#if defined(USE_LCD_HDMI) + HDMI_IO_Init(); + + HDMI_IO_Delay(120); + + if(ADV7533_ID == adv7533_drv.ReadID(ADV7533_CEC_DSI_I2C_ADDR)) + { + return ADV7533_ID; + } + else if(((HDMI_IO_Read(LCD_DSI_ADDRESS, LCD_DSI_ID_REG) == LCD_DSI_ID)) || \ + (HDMI_IO_Read(LCD_DSI_ADDRESS_A02, LCD_DSI_ID_REG) == LCD_DSI_ID)) + { + return LCD_DSI_ID; + } + else + { + return 0; + } +#else + return LCD_DSI_ID; +#endif /* USE_LCD_HDMI */ +} + +/******************************************************************************* + LTDC, DMA2D and DSI BSP Routines +*******************************************************************************/ +/** + * @brief De-Initializes the BSP LCD Msp + * Application can surcharge if needed this function implementation. + */ +__weak void BSP_LCD_MspDeInit(void) +{ + /** @brief Disable IRQ of LTDC IP */ + HAL_NVIC_DisableIRQ(LTDC_IRQn); + + /** @brief Disable IRQ of DMA2D IP */ + HAL_NVIC_DisableIRQ(DMA2D_IRQn); + + /** @brief Disable IRQ of DSI IP */ + HAL_NVIC_DisableIRQ(DSI_IRQn); + + /** @brief Force and let in reset state LTDC, DMA2D and DSI Host + Wrapper IPs */ + __HAL_RCC_LTDC_FORCE_RESET(); + __HAL_RCC_DMA2D_FORCE_RESET(); + __HAL_RCC_DSI_FORCE_RESET(); + + /** @brief Disable the LTDC, DMA2D and DSI Host and Wrapper clocks */ + __HAL_RCC_LTDC_CLK_DISABLE(); + __HAL_RCC_DMA2D_CLK_DISABLE(); + __HAL_RCC_DSI_CLK_DISABLE(); +} + +/** + * @brief Initialize the BSP LCD Msp. + * Application can surcharge if needed this function implementation + */ +__weak void BSP_LCD_MspInit(void) +{ + /** @brief Enable the LTDC clock */ + __HAL_RCC_LTDC_CLK_ENABLE(); + + /** @brief Toggle Sw reset of LTDC IP */ + __HAL_RCC_LTDC_FORCE_RESET(); + __HAL_RCC_LTDC_RELEASE_RESET(); + + /** @brief Enable the DMA2D clock */ + __HAL_RCC_DMA2D_CLK_ENABLE(); + + /** @brief Toggle Sw reset of DMA2D IP */ + __HAL_RCC_DMA2D_FORCE_RESET(); + __HAL_RCC_DMA2D_RELEASE_RESET(); + + /** @brief Enable DSI Host and wrapper clocks */ + __HAL_RCC_DSI_CLK_ENABLE(); + + /** @brief Soft Reset the DSI Host and wrapper */ + __HAL_RCC_DSI_FORCE_RESET(); + __HAL_RCC_DSI_RELEASE_RESET(); + + /** @brief NVIC configuration for LTDC interrupt that is now enabled */ + HAL_NVIC_SetPriority(LTDC_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(LTDC_IRQn); + + /** @brief NVIC configuration for DMA2D interrupt that is now enabled */ + HAL_NVIC_SetPriority(DMA2D_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DMA2D_IRQn); + + /** @brief NVIC configuration for DSI interrupt that is now enabled */ + HAL_NVIC_SetPriority(DSI_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(DSI_IRQn); +} + +/** + * @brief Draws a pixel on LCD. + * @param Xpos: X position + * @param Ypos: Y position + * @param RGB_Code: Pixel color in ARGB mode (8-8-8-8) + */ +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t RGB_Code) +{ + /* Write data value to all SDRAM memory */ + *(__IO uint32_t*) (hltdc_eval.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))) = RGB_Code; +} + + +/** + * @brief Draws a character on LCD. + * @param Xpos: Line where to display the character shape + * @param Ypos: Start column address + * @param c: Pointer to the character data + */ +static void DrawChar(uint16_t Xpos, uint16_t Ypos, const uint8_t *c) +{ + uint32_t i = 0, j = 0; + uint16_t height, width; + uint8_t offset; + uint8_t *pchar; + uint32_t line; + + height = DrawProp[ActiveLayer].pFont->Height; + width = DrawProp[ActiveLayer].pFont->Width; + + offset = 8 *((width + 7)/8) - width ; + + for(i = 0; i < height; i++) + { + pchar = ((uint8_t *)c + (width + 7)/8 * i); + + switch(((width + 7)/8)) + { + + case 1: + line = pchar[0]; + break; + + case 2: + line = (pchar[0]<< 8) | pchar[1]; + break; + + case 3: + default: + line = (pchar[0]<< 16) | (pchar[1]<< 8) | pchar[2]; + break; + } + + for (j = 0; j < width; j++) + { + if(line & (1 << (width- j + offset- 1))) + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp[ActiveLayer].TextColor); + } + else + { + BSP_LCD_DrawPixel((Xpos + j), Ypos, DrawProp[ActiveLayer].BackColor); + } + } + Ypos++; + } +} + +/** + * @brief Fills a triangle (between 3 points). + * @param x1: Point 1 X position + * @param y1: Point 1 Y position + * @param x2: Point 2 X position + * @param y2: Point 2 Y position + * @param x3: Point 3 X position + * @param y3: Point 3 Y position + */ +static void FillTriangle(uint16_t x1, uint16_t x2, uint16_t x3, uint16_t y1, uint16_t y2, uint16_t y3) +{ + int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0, + yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0, + curpixel = 0; + + deltax = ABS(x2 - x1); /* The difference between the x's */ + deltay = ABS(y2 - y1); /* The difference between the y's */ + x = x1; /* Start x off at the first pixel */ + y = y1; /* Start y off at the first pixel */ + + if (x2 >= x1) /* The x-values are increasing */ + { + xinc1 = 1; + xinc2 = 1; + } + else /* The x-values are decreasing */ + { + xinc1 = -1; + xinc2 = -1; + } + + if (y2 >= y1) /* The y-values are increasing */ + { + yinc1 = 1; + yinc2 = 1; + } + else /* The y-values are decreasing */ + { + yinc1 = -1; + yinc2 = -1; + } + + if (deltax >= deltay) /* There is at least one x-value for every y-value */ + { + xinc1 = 0; /* Don't change the x when numerator >= denominator */ + yinc2 = 0; /* Don't change the y for every iteration */ + den = deltax; + num = deltax / 2; + numadd = deltay; + numpixels = deltax; /* There are more x-values than y-values */ + } + else /* There is at least one y-value for every x-value */ + { + xinc2 = 0; /* Don't change the x for every iteration */ + yinc1 = 0; /* Don't change the y when numerator >= denominator */ + den = deltay; + num = deltay / 2; + numadd = deltax; + numpixels = deltay; /* There are more y-values than x-values */ + } + + for (curpixel = 0; curpixel <= numpixels; curpixel++) + { + BSP_LCD_DrawLine(x, y, x3, y3); + + num += numadd; /* Increase the numerator by the top of the fraction */ + if (num >= den) /* Check if numerator >= denominator */ + { + num -= den; /* Calculate the new numerator value */ + x += xinc1; /* Change the x as appropriate */ + y += yinc1; /* Change the y as appropriate */ + } + x += xinc2; /* Change the x as appropriate */ + y += yinc2; /* Change the y as appropriate */ + } +} + +/** + * @brief Fills a buffer. + * @param LayerIndex: Layer index + * @param pDst: Pointer to destination buffer + * @param xSize: Buffer width + * @param ySize: Buffer height + * @param OffLine: Offset + * @param ColorIndex: Color index + */ +static void LL_FillBuffer(uint32_t LayerIndex, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t OffLine, uint32_t ColorIndex) +{ + /* Register to memory mode with ARGB8888 as color Mode */ + hdma2d_eval.Init.Mode = DMA2D_R2M; + hdma2d_eval.Init.ColorMode = DMA2D_OUTPUT_ARGB8888; + hdma2d_eval.Init.OutputOffset = OffLine; + + hdma2d_eval.Instance = DMA2D; + + /* DMA2D Initialization */ + if(HAL_DMA2D_Init(&hdma2d_eval) == HAL_OK) + { + if(HAL_DMA2D_ConfigLayer(&hdma2d_eval, LayerIndex) == HAL_OK) + { + if (HAL_DMA2D_Start(&hdma2d_eval, ColorIndex, (uint32_t)pDst, xSize, ySize) == HAL_OK) + { + /* Polling For DMA transfer */ + HAL_DMA2D_PollForTransfer(&hdma2d_eval, 10); + } + } + } +} + +/** + * @brief Converts a line to an ARGB8888 pixel format. + * @param pSrc: Pointer to source buffer + * @param pDst: Output color + * @param xSize: Buffer width + * @param ColorMode: Input color mode + */ +static void LL_ConvertLineToARGB8888(void *pSrc, void *pDst, uint32_t xSize, uint32_t ColorMode) +{ + /* Configure the DMA2D Mode, Color Mode and output offset */ + hdma2d_eval.Init.Mode = DMA2D_M2M_PFC; + hdma2d_eval.Init.ColorMode = DMA2D_OUTPUT_ARGB8888; + hdma2d_eval.Init.OutputOffset = 0; + + /* Foreground Configuration */ + hdma2d_eval.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; + hdma2d_eval.LayerCfg[1].InputAlpha = 0xFF; + hdma2d_eval.LayerCfg[1].InputColorMode = ColorMode; + hdma2d_eval.LayerCfg[1].InputOffset = 0; + + hdma2d_eval.Instance = DMA2D; + + /* DMA2D Initialization */ + if(HAL_DMA2D_Init(&hdma2d_eval) == HAL_OK) + { + if(HAL_DMA2D_ConfigLayer(&hdma2d_eval, 1) == HAL_OK) + { + if (HAL_DMA2D_Start(&hdma2d_eval, (uint32_t)pSrc, (uint32_t)pDst, xSize, 1) == HAL_OK) + { + /* Polling For DMA transfer */ + HAL_DMA2D_PollForTransfer(&hdma2d_eval, 10); + } + } + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_lcd.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_lcd.h new file mode 100644 index 00000000..c2257587 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_lcd.h @@ -0,0 +1,424 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_lcd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_eval_lcd.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_EVAL_LCD_H +#define __STM32F769I_EVAL_LCD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +/* Include LCD component Driver */ + +/* Include OTM8009A LCD Driver IC driver code */ +#include "../Components/otm8009a/otm8009a.h" + +#if defined(USE_LCD_HDMI) +/* Include ADV7533 HDMI Driver IC driver code */ +#include "../Components/adv7533/adv7533.h" +#endif /* USE_LCD_HDMI */ + +/* Include SDRAM Driver */ +#include "stm32f769i_eval_sdram.h" +#include "stm32f769i_eval.h" + +#include "../../../Utilities/Fonts/fonts.h" + +#include /* use of memset() */ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @addtogroup STM32F769I_EVAL_LCD + * @{ + */ + +/** @defgroup STM32F769I_EVAL_LCD_Exported_Constants STM32F769I EVAL LCD Exported Constants + * @{ + */ +#define BSP_LCD_DMA2D_IRQHandler DMA2D_IRQHandler +#define BSP_LCD_DSI_IRQHandler DSI_IRQHandler +#define BSP_LCD_LTDC_IRQHandler LTDC_IRQHandler +#define BSP_LCD_LTDC_ER_IRQHandler LTDC_ER_IRQHandler + + +#define LCD_LayerCfgTypeDef LTDC_LayerCfgTypeDef +/** + * @brief LCD FB_StartAddress + */ +#define LCD_FB_START_ADDRESS ((uint32_t)0xC0000000) + +/** @brief Maximum number of LTDC layers + */ +#define LTDC_MAX_LAYER_NUMBER ((uint32_t) 2) + +/** @brief LTDC Background layer index + */ +#define LTDC_ACTIVE_LAYER_BACKGROUND ((uint32_t) 0) + +/** @brief LTDC Foreground layer index + */ +#define LTDC_ACTIVE_LAYER_FOREGROUND ((uint32_t) 1) + +/** @brief Number of LTDC layers + */ +#define LTDC_NB_OF_LAYERS ((uint32_t) 2) + +/** @brief LTDC Default used layer index + */ +#define LTDC_DEFAULT_ACTIVE_LAYER LTDC_ACTIVE_LAYER_FOREGROUND + +/** + * @brief LCD status structure definition + */ +#define LCD_OK 0x00 +#define LCD_ERROR 0x01 +#define LCD_TIMEOUT 0x02 + +/** + * @brief LCD Display OTM8009A DSI Virtual Channel ID + */ +#define LCD_OTM8009A_ID ((uint32_t) 0) + +#if defined(USE_LCD_HDMI) +/** + * @brief HDMI ADV7533 DSI Virtual Channel ID + */ +#define HDMI_ADV7533_ID ((uint32_t) 0) + +/** + * @brief HDMI Foramt + */ +#define HDMI_FORMAT_720_480 ((uint8_t) 0x00) /*720_480 format choice of HDMI display */ +#define HDMI_FORMAT_720_576 ((uint8_t) 0x01) /*720_576 format choice of HDMI display*/ + +#endif /* USE_LCD_HDMI */ + +/** + * @brief LCD color definitions values + * in ARGB8888 format. + */ + +/** @brief Blue value in ARGB8888 format + */ +#define LCD_COLOR_BLUE ((uint32_t) 0xFF0000FF) + +/** @brief Green value in ARGB8888 format + */ +#define LCD_COLOR_GREEN ((uint32_t) 0xFF00FF00) + +/** @brief Red value in ARGB8888 format + */ +#define LCD_COLOR_RED ((uint32_t) 0xFFFF0000) + +/** @brief Cyan value in ARGB8888 format + */ +#define LCD_COLOR_CYAN ((uint32_t) 0xFF00FFFF) + +/** @brief Magenta value in ARGB8888 format + */ +#define LCD_COLOR_MAGENTA ((uint32_t) 0xFFFF00FF) + +/** @brief Yellow value in ARGB8888 format + */ +#define LCD_COLOR_YELLOW ((uint32_t) 0xFFFFFF00) + +/** @brief Light Blue value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTBLUE ((uint32_t) 0xFF8080FF) + +/** @brief Light Green value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTGREEN ((uint32_t) 0xFF80FF80) + +/** @brief Light Red value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTRED ((uint32_t) 0xFFFF8080) + +/** @brief Light Cyan value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTCYAN ((uint32_t) 0xFF80FFFF) + +/** @brief Light Magenta value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTMAGENTA ((uint32_t) 0xFFFF80FF) + +/** @brief Light Yellow value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTYELLOW ((uint32_t) 0xFFFFFF80) + +/** @brief Dark Blue value in ARGB8888 format + */ +#define LCD_COLOR_DARKBLUE ((uint32_t) 0xFF000080) + +/** @brief Light Dark Green value in ARGB8888 format + */ +#define LCD_COLOR_DARKGREEN ((uint32_t) 0xFF008000) + +/** @brief Light Dark Red value in ARGB8888 format + */ +#define LCD_COLOR_DARKRED ((uint32_t) 0xFF800000) + +/** @brief Dark Cyan value in ARGB8888 format + */ +#define LCD_COLOR_DARKCYAN ((uint32_t) 0xFF008080) + +/** @brief Dark Magenta value in ARGB8888 format + */ +#define LCD_COLOR_DARKMAGENTA ((uint32_t) 0xFF800080) + +/** @brief Dark Yellow value in ARGB8888 format + */ +#define LCD_COLOR_DARKYELLOW ((uint32_t) 0xFF808000) + +/** @brief White value in ARGB8888 format + */ +#define LCD_COLOR_WHITE ((uint32_t) 0xFFFFFFFF) + +/** @brief Light Gray value in ARGB8888 format + */ +#define LCD_COLOR_LIGHTGRAY ((uint32_t) 0xFFD3D3D3) + +/** @brief Gray value in ARGB8888 format + */ +#define LCD_COLOR_GRAY ((uint32_t) 0xFF808080) + +/** @brief Dark Gray value in ARGB8888 format + */ +#define LCD_COLOR_DARKGRAY ((uint32_t) 0xFF404040) + +/** @brief Black value in ARGB8888 format + */ +#define LCD_COLOR_BLACK ((uint32_t) 0xFF000000) + +/** @brief Brown value in ARGB8888 format + */ +#define LCD_COLOR_BROWN ((uint32_t) 0xFFA52A2A) + +/** @brief Orange value in ARGB8888 format + */ +#define LCD_COLOR_ORANGE ((uint32_t) 0xFFFFA500) + +/** @brief Transparent value in ARGB8888 format + */ +#define LCD_COLOR_TRANSPARENT ((uint32_t) 0xFF000000) + +/** + * @brief LCD default font + */ +#define LCD_DEFAULT_FONT Font24 + +/** + * @brief Possible values of + * pixel data format (ie color coding) transmitted on DSI Data lane in DSI packets + */ + +#define LCD_DSI_PIXEL_DATA_FMT_RBG888 DSI_RGB888 /*!< DSI packet pixel format chosen is RGB888 : 24 bpp */ +#define LCD_DSI_PIXEL_DATA_FMT_RBG565 DSI_RGB565 /*!< DSI packet pixel format chosen is RGB565 : 16 bpp */ + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LCD_Exported_Types STM32F769I EVAL LCD Exported Types + * @{ + */ + +/** +* @brief LCD Drawing main properties +*/ +typedef struct +{ + uint32_t TextColor; /*!< Specifies the color of text */ + uint32_t BackColor; /*!< Specifies the background color below the text */ + sFONT *pFont; /*!< Specifies the font used for the text */ + +} LCD_DrawPropTypeDef; + +/** + * @brief LCD Drawing point (pixel) geometric definition + */ +typedef struct +{ + int16_t X; /*!< geometric X position of drawing */ + int16_t Y; /*!< geometric Y position of drawing */ + +} Point; + +/** + * @brief Pointer on LCD Drawing point (pixel) geometric definition + */ +typedef Point * pPoint; + +/** + * @brief LCD drawing Line alignment mode definitions + */ +typedef enum +{ + CENTER_MODE = 0x01, /*!< Center mode */ + RIGHT_MODE = 0x02, /*!< Right mode */ + LEFT_MODE = 0x03 /*!< Left mode */ + +} Text_AlignModeTypdef; + + +/** + * @brief LCD_OrientationTypeDef + * Possible values of Display Orientation + */ +typedef enum +{ + LCD_ORIENTATION_PORTRAIT = 0x00, /*!< Portrait orientation choice of LCD screen */ + LCD_ORIENTATION_LANDSCAPE = 0x01, /*!< Landscape orientation choice of LCD screen */ + LCD_ORIENTATION_INVALID = 0x02 /*!< Invalid orientation choice of LCD screen */ +} LCD_OrientationTypeDef; + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LCD_Exported_Macro STM32F769I EVAL LCD Exported Macro + * @{ + */ +/** + * @} + */ +/** @addtogroup STM32F769I_EVAL_LCD_Exported_Functions + * @{ + */ +uint8_t BSP_LCD_Init(void); +uint8_t BSP_LCD_InitEx(LCD_OrientationTypeDef orientation); + +#if defined(USE_LCD_HDMI) +uint8_t BSP_LCD_HDMIInitEx(uint8_t format); +#endif /* USE_LCD_HDMI */ + +void BSP_LCD_MspDeInit(void); +void BSP_LCD_MspInit(void); +void BSP_LCD_Reset(void); + +uint32_t BSP_LCD_GetXSize(void); +uint32_t BSP_LCD_GetYSize(void); +void BSP_LCD_SetXSize(uint32_t imageWidthPixels); +void BSP_LCD_SetYSize(uint32_t imageHeightPixels); + +void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address); +void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency); +void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address); +void BSP_LCD_SetColorKeying(uint32_t LayerIndex, uint32_t RGBValue); +void BSP_LCD_ResetColorKeying(uint32_t LayerIndex); +void BSP_LCD_SetLayerWindow(uint16_t LayerIndex, uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); + +void BSP_LCD_SelectLayer(uint32_t LayerIndex); +void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState State); + +void BSP_LCD_SetTextColor(uint32_t Color); +uint32_t BSP_LCD_GetTextColor(void); +void BSP_LCD_SetBackColor(uint32_t Color); +uint32_t BSP_LCD_GetBackColor(void); +void BSP_LCD_SetFont(sFONT *fonts); +sFONT *BSP_LCD_GetFont(void); + +uint32_t BSP_LCD_ReadPixel(uint16_t Xpos, uint16_t Ypos); +void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t pixel); +void BSP_LCD_Clear(uint32_t Color); +void BSP_LCD_ClearStringLine(uint32_t Line); +void BSP_LCD_DisplayStringAtLine(uint16_t Line, uint8_t *ptr); +void BSP_LCD_DisplayStringAt(uint16_t Xpos, uint16_t Ypos, uint8_t *Text, Text_AlignModeTypdef Mode); +void BSP_LCD_DisplayChar(uint16_t Xpos, uint16_t Ypos, uint8_t Ascii); + +void BSP_LCD_DrawHLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawVLine(uint16_t Xpos, uint16_t Ypos, uint16_t Length); +void BSP_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); +void BSP_LCD_DrawRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_DrawCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_DrawPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_DrawEllipse(int Xpos, int Ypos, int XRadius, int YRadius); +void BSP_LCD_DrawBitmap(uint32_t Xpos, uint32_t Ypos, uint8_t *pbmp); + +void BSP_LCD_FillRect(uint16_t Xpos, uint16_t Ypos, uint16_t Width, uint16_t Height); +void BSP_LCD_FillCircle(uint16_t Xpos, uint16_t Ypos, uint16_t Radius); +void BSP_LCD_FillPolygon(pPoint Points, uint16_t PointCount); +void BSP_LCD_FillEllipse(int Xpos, int Ypos, int XRadius, int YRadius); + +void BSP_LCD_DisplayOff(void); +void BSP_LCD_DisplayOn(void); +void BSP_LCD_SetBrightness(uint8_t BrightnessValue); +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_LCD_Exported_Variables STM32F769I EVAL LCD Exported Variables + * @{ + */ + +/* @brief DMA2D handle variable */ +extern DMA2D_HandleTypeDef hdma2d_eval; + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_EVAL_LCD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_nor.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_nor.c new file mode 100644 index 00000000..560b8790 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_nor.c @@ -0,0 +1,461 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_nor.c + * @author MCD Application Team + * @brief This file includes a standard driver for the PC28F128M29EWLA NOR flash memory + * device mounted on STM32F769I-EVAL evaluation boards. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the PC28F128M29EWLA NOR flash external memory mounted + on STM32F769I-EVAL evaluation board. + - This driver does not need a specific component driver for the NOR device + to be included with. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the NOR external memory using the BSP_NOR_Init() function. This + function includes the MSP layer hardware resources initialization and the + FMC controller configuration to interface with the external NOR memory. + + + NOR flash operations + o NOR external memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_NOR_ReadData()/BSP_NOR_WriteData(). The BSP_NOR_WriteData() performs write operation + of an amount of data by unit (halfword). You can also perform a program data + operation of an amount of data using the function BSP_NOR_ProgramData(). + o The function BSP_NOR_Read_ID() returns the chip IDs stored in the structure + "NOR_IDTypeDef". (see the NOR IDs in the memory data sheet) + o Perform erase block operation using the function BSP_NOR_Erase_Block() and by + specifying the block address. You can perform an erase operation of the whole + chip by calling the function BSP_NOR_Erase_Chip(). + o After other operations, the function BSP_NOR_ReturnToReadMode() allows the NOR + flash to return to read mode to perform read operations on it. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_nor.c +- stm32f7xx_ll_fmc.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval_nor.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_NOR STM32F769I_EVAL NOR + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ + +/** @defgroup STM32F769I_EVAL_NOR_Private_Types_Definitions NOR Private Types Definitions + * @{ + */ +/** + * @} + */ +/* Private define ------------------------------------------------------------*/ + +/** @defgroup STM32F769I_EVAL_NOR_Private_Defines NOR Private Defines + * @{ + */ +/** + * @} + */ +/* Private macro -------------------------------------------------------------*/ + +/** @defgroup STM32F769I_EVAL_NOR_Private_Macros NOR Private Macros + * @{ + */ +/** + * @} + */ +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup STM32F769I_EVAL_NOR_Private_Variables NOR Private Variables + * @{ + */ +NOR_HandleTypeDef norHandle; +static FMC_NORSRAM_TimingTypeDef Timing; + +/** + * @} + */ + +/* Private function prototypes -----------------------------------------------*/ + +/** @defgroup STM32F769I_EVAL_NOR_Private_Functions_Prototypes NOR Private Functions Prototypes + * @{ + */ +/** + * @} + */ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup STM32F769I_EVAL_NOR_Private_Functions NOR Private Functions + * @{ + */ + +/** + * @brief Initializes the NOR device. + * @retval NOR memory status + */ +uint8_t BSP_NOR_Init(void) +{ + static uint8_t nor_status = NOR_STATUS_ERROR; + norHandle.Instance = FMC_NORSRAM_DEVICE; + norHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + /* NOR device configuration */ + /* Timing configuration derived from system clock (up to 216Mhz) + for 108Mhz as NOR clock frequency */ + Timing.AddressSetupTime = 4; + Timing.AddressHoldTime = 3; + Timing.DataSetupTime = 8; + Timing.BusTurnAroundDuration = 1; + Timing.CLKDivision = 2; + Timing.DataLatency = 2; + Timing.AccessMode = FMC_ACCESS_MODE_A; + + norHandle.Init.NSBank = FMC_NORSRAM_BANK1; + norHandle.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; + norHandle.Init.MemoryType = FMC_MEMORY_TYPE_NOR; + norHandle.Init.MemoryDataWidth = NOR_MEMORY_WIDTH; + norHandle.Init.BurstAccessMode = NOR_BURSTACCESS; + norHandle.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; + norHandle.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; + norHandle.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; + norHandle.Init.WaitSignal = FMC_WAIT_SIGNAL_ENABLE; + norHandle.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; + norHandle.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_ENABLE; + norHandle.Init.WriteBurst = NOR_WRITEBURST; + norHandle.Init.ContinuousClock = CONTINUOUSCLOCK_FEATURE; + + /* NOR controller initialization */ + BSP_NOR_MspInit(&norHandle, NULL); /* __weak function can be rewritten by the application */ + + if(HAL_NOR_Init(&norHandle, &Timing, &Timing) != HAL_OK) + { + nor_status = NOR_STATUS_ERROR; + } + else + { + nor_status = NOR_STATUS_OK; + } + return nor_status; +} + +/** + * @brief DeInitializes the NOR device. + * @retval NOR status + */ +uint8_t BSP_NOR_DeInit(void) +{ + static uint8_t nor_status = NOR_STATUS_ERROR; + /* NOR device de-initialization */ + norHandle.Instance = FMC_NORSRAM_DEVICE; + norHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + if(HAL_NOR_DeInit(&norHandle) != HAL_OK) + { + nor_status = NOR_STATUS_ERROR; + } + else + { + nor_status = NOR_STATUS_OK; + } + + /* NOR controller de-initialization */ + BSP_NOR_MspDeInit(&norHandle, NULL); + + return nor_status; +} + +/** + * @brief Reads an amount of data from the NOR device. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of data to read + * @retval NOR memory status + */ +uint8_t BSP_NOR_ReadData(uint32_t uwStartAddress, uint16_t* pData, uint32_t uwDataSize) +{ + if(HAL_NOR_ReadBuffer(&norHandle, NOR_DEVICE_ADDR + uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return NOR_STATUS_ERROR; + } + else + { + return NOR_STATUS_OK; + } +} + +/** + * @brief Returns the NOR memory to read mode. + * @retval None + */ +void BSP_NOR_ReturnToReadMode(void) +{ + HAL_NOR_ReturnToReadMode(&norHandle); +} + +/** + * @brief Writes an amount of data to the NOR device. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of data to write + * @retval NOR memory status + */ +uint8_t BSP_NOR_WriteData(uint32_t uwStartAddress, uint16_t* pData, uint32_t uwDataSize) +{ + uint32_t index = uwDataSize; + + while(index > 0) + { + /* Write data to NOR */ + HAL_NOR_Program(&norHandle, (uint32_t *)(NOR_DEVICE_ADDR + uwStartAddress), pData); + + /* Read NOR device status */ + if(HAL_NOR_GetStatus(&norHandle, NOR_DEVICE_ADDR, PROGRAM_TIMEOUT) != HAL_NOR_STATUS_SUCCESS) + { + return NOR_STATUS_ERROR; + } + + /* Update the counters */ + index--; + uwStartAddress += 2; + pData++; + } + + return NOR_STATUS_OK; +} + +/** + * @brief Programs an amount of data to the NOR device. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of data to write + * @retval NOR memory status + */ +uint8_t BSP_NOR_ProgramData(uint32_t uwStartAddress, uint16_t* pData, uint32_t uwDataSize) +{ + /* Send NOR program buffer operation */ + HAL_NOR_ProgramBuffer(&norHandle, uwStartAddress, pData, uwDataSize); + + /* Return the NOR memory status */ + if(HAL_NOR_GetStatus(&norHandle, NOR_DEVICE_ADDR, PROGRAM_TIMEOUT) != HAL_NOR_STATUS_SUCCESS) + { + return NOR_STATUS_ERROR; + } + else + { + return NOR_STATUS_OK; + } +} + +/** + * @brief Erases the specified block of the NOR device. + * @param BlockAddress: Block address to erase + * @retval NOR memory status + */ +uint8_t BSP_NOR_Erase_Block(uint32_t BlockAddress) +{ + /* Send NOR erase block operation */ + HAL_NOR_Erase_Block(&norHandle, BlockAddress, NOR_DEVICE_ADDR); + + /* Return the NOR memory status */ + if(HAL_NOR_GetStatus(&norHandle, NOR_DEVICE_ADDR, BLOCKERASE_TIMEOUT) != HAL_NOR_STATUS_SUCCESS) + { + return NOR_STATUS_ERROR; + } + else + { + return NOR_STATUS_OK; + } +} + +/** + * @brief Erases the entire NOR chip. + * @retval NOR memory status + */ +uint8_t BSP_NOR_Erase_Chip(void) +{ + /* Send NOR Erase chip operation */ + HAL_NOR_Erase_Chip(&norHandle, NOR_DEVICE_ADDR); + + /* Return the NOR memory status */ + if(HAL_NOR_GetStatus(&norHandle, NOR_DEVICE_ADDR, CHIPERASE_TIMEOUT) != HAL_NOR_STATUS_SUCCESS) + { + return NOR_STATUS_ERROR; + } + else + { + return NOR_STATUS_OK; + } +} + +/** + * @brief Reads NOR flash IDs. + * @param pNOR_ID : Pointer to NOR ID structure + * @retval NOR memory status + */ +uint8_t BSP_NOR_Read_ID(NOR_IDTypeDef *pNOR_ID) +{ + if(HAL_NOR_Read_ID(&norHandle, pNOR_ID) != HAL_OK) + { + return NOR_STATUS_ERROR; + } + else + { + return NOR_STATUS_OK; + } +} + +/** + * @brief Initializes the NOR MSP. + * @param norHandle: NOR handle + * @param Params + * @retval None + */ +__weak void BSP_NOR_MspInit(NOR_HandleTypeDef *norHandle, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /* Enable FMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + + /* GPIOC configuration */ + gpio_init_structure.Alternate = GPIO_AF9_FMC; + gpio_init_structure.Pin = GPIO_PIN_6 | GPIO_PIN_7; + HAL_GPIO_Init(GPIOC, &gpio_init_structure); + + /* GPIOD configuration */ + gpio_init_structure.Alternate = GPIO_AF12_FMC; + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5|\ + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 |\ + GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOE configuration */ + gpio_init_structure.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 |\ + GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 |\ + GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOF configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOF, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); +} + +/** + * @brief DeInitializes NOR MSP. + * @param norHandle: NOR handle + * @param Params + * @retval None + */ +__weak void BSP_NOR_MspDeInit(NOR_HandleTypeDef *norHandle, void *Params) +{ + /* GPIO pins clock, FMC clock can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief NOR BSP Wait for Ready/Busy signal. + * @param norHandle: Pointer to NOR handle + * @param Timeout: Timeout duration + * @retval None + */ +void HAL_NOR_MspWait(NOR_HandleTypeDef *norHandle, uint32_t Timeout) +{ + uint32_t timeout = Timeout; + + /* Polling on Ready/Busy signal */ + while((HAL_GPIO_ReadPin(NOR_READY_BUSY_GPIO, NOR_READY_BUSY_PIN) != NOR_BUSY_STATE) && (timeout > 0)) + { + timeout--; + } + + timeout = Timeout; + + /* Polling on Ready/Busy signal */ + while((HAL_GPIO_ReadPin(NOR_READY_BUSY_GPIO, NOR_READY_BUSY_PIN) != NOR_READY_STATE) && (timeout > 0)) + { + timeout--; + } +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_nor.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_nor.h new file mode 100644 index 00000000..c41a0dc5 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_nor.h @@ -0,0 +1,152 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_nor.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_eval_nor.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_EVAL_NOR_H +#define __STM32F769I_EVAL_NOR_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @addtogroup STM32F769I_EVAL_NOR + * @{ + */ + +/** @defgroup STM32F769I_EVAL_NOR_Exported_Types NOR Exported Types + * @{ + */ +/** + * @} + */ + +/** + * @brief NOR status structure definition + */ +#define NOR_STATUS_OK ((uint8_t)0x00) +#define NOR_STATUS_ERROR ((uint8_t)0x01) + +/** @defgroup STM32F769I_EVAL_NOR_Exported_Constants NOR Exported Constants + * @{ + */ +#define NOR_DEVICE_ADDR ((uint32_t)0x60000000) + +/* #define NOR_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_8 */ +#define NOR_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_16 + +#define NOR_BURSTACCESS FMC_BURST_ACCESS_MODE_DISABLE +/* #define NOR_BURSTACCESS FMC_BURST_ACCESS_MODE_ENABLE*/ + +#define NOR_WRITEBURST FMC_WRITE_BURST_DISABLE +/* #define NOR_WRITEBURST FMC_WRITE_BURST_ENABLE */ + +#define CONTINUOUSCLOCK_FEATURE FMC_CONTINUOUS_CLOCK_SYNC_ONLY +/* #define CONTINUOUSCLOCK_FEATURE FMC_CONTINUOUS_CLOCK_SYNC_ASYNC */ + +/* NOR operations Timeout definitions */ +#define BLOCKERASE_TIMEOUT ((uint32_t)0x00A00000) /* NOR block erase timeout */ +#define CHIPERASE_TIMEOUT ((uint32_t)0x30000000) /* NOR chip erase timeout */ +#define PROGRAM_TIMEOUT ((uint32_t)0x00004400) /* NOR program timeout */ + +/* NOR Ready/Busy signal GPIO definitions */ +#define NOR_READY_BUSY_PIN GPIO_PIN_6 +#define NOR_READY_BUSY_GPIO GPIOC +#define NOR_READY_STATE GPIO_PIN_SET +#define NOR_BUSY_STATE GPIO_PIN_RESET + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_NOR_Exported_Macro NOR Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_NOR_Exported_Functions NOR Exported Functions + * @{ + */ +uint8_t BSP_NOR_Init(void); +uint8_t BSP_NOR_DeInit(void); +uint8_t BSP_NOR_ReadData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_NOR_WriteData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_NOR_ProgramData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_NOR_Erase_Block(uint32_t BlockAddress); +uint8_t BSP_NOR_Erase_Chip(void); +uint8_t BSP_NOR_Read_ID(NOR_IDTypeDef *pNOR_ID); +void BSP_NOR_ReturnToReadMode(void); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_NOR_MspInit(NOR_HandleTypeDef *hnor, void *Params); +void BSP_NOR_MspDeInit(NOR_HandleTypeDef *hnor, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_EVAL_NOR_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_qspi.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_qspi.c new file mode 100644 index 00000000..ed1f59f5 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_qspi.c @@ -0,0 +1,851 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_qspi.c + * @author MCD Application Team + * @brief This file includes a standard driver for the N25Q512A QSPI + * memory mounted on STM32F769I-EVAL board. + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + (#) This driver is used to drive the N25Q512A QSPI external + memory mounted on STM32F769I-EVAL evaluation board. + + (#) This driver need a specific component driver (N25Q512A) to be included with. + + (#) Initialization steps: + (++) Initialize the QPSI external memory using the BSP_QSPI_Init() function. This + function includes the MSP layer hardware resources initialization and the + QSPI interface with the external memory. + + (#) QSPI memory operations + (++) QSPI memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_QSPI_Read()/BSP_QSPI_Write(). + (++) The function BSP_QSPI_GetInfo() returns the configuration of the QSPI memory. + (see the QSPI memory data sheet) + (++) Perform erase block operation using the function BSP_QSPI_Erase_Block() and by + specifying the block address. You can perform an erase operation of the whole + chip by calling the function BSP_QSPI_Erase_Chip(). + (++) The function BSP_QSPI_GetStatus() returns the current status of the QSPI memory. + (see the QSPI memory data sheet) + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_qspi.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +- n25q512a.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval_qspi.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_QSPI STM32F769I_EVAL QSPI + * @{ + */ + + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup STM32F769I_EVAL_QSPI_Private_Variables Private Variables + * @{ + */ +QSPI_HandleTypeDef QSPIHandle; + +/** + * @} + */ + + + +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup STM32F769I_EVAL_QSPI_Private_Functions Private Functions + * @{ + */ +static uint8_t QSPI_ResetMemory (QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_DummyCyclesCfg (QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_WriteEnable (QSPI_HandleTypeDef *hqspi); +static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout); + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_QSPI_Exported_Functions Exported Functions + * @{ + */ + +/** + * @brief Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Init(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level initialization */ + BSP_QSPI_MspInit(&QSPIHandle, NULL); + + /* QSPI initialization */ + /* QSPI freq = SYSCLK /(1 + ClockPrescaler) = 216 MHz/(1+1) = 108 Mhz */ + QSPIHandle.Init.ClockPrescaler = 1; + QSPIHandle.Init.FifoThreshold = 4; + QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE; + QSPIHandle.Init.FlashSize = POSITION_VAL(N25Q512A_FLASH_SIZE) - 1; + QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE; /* Min 50ns for nonRead */ + QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0; + QSPIHandle.Init.FlashID = QSPI_FLASH_ID_1; + QSPIHandle.Init.DualFlash = QSPI_DUALFLASH_DISABLE; + + if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* QSPI memory reset */ + if (QSPI_ResetMemory(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Set the QSPI memory in 4-bytes address mode */ + if (QSPI_EnterFourBytesAddress(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + /* Configuration of the dummy cycles on QSPI memory side */ + if (QSPI_DummyCyclesCfg(&QSPIHandle) != QSPI_OK) + { + return QSPI_NOT_SUPPORTED; + } + + return QSPI_OK; +} + +/** + * @brief De-Initializes the QSPI interface. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_DeInit(void) +{ + QSPIHandle.Instance = QUADSPI; + + /* Call the DeInit function to reset the driver */ + if (HAL_QSPI_DeInit(&QSPIHandle) != HAL_OK) + { + return QSPI_ERROR; + } + + /* System level De-initialization */ + BSP_QSPI_MspDeInit(&QSPIHandle, NULL); + + return QSPI_OK; +} + +/** + * @brief Reads an amount of data from the QSPI memory. + * @param pData: Pointer to data to be read + * @param ReadAddr: Read start address + * @param Size: Size of data to read + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the read command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = QUAD_OUT_FAST_READ_CMD; + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.Address = ReadAddr; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = N25Q512A_DUMMY_CYCLES_READ_QUAD; + s_command.NbData = Size; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Set S# timing for Read command */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_3_CYCLE); + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Restore S# timing for nonRead commands */ + MODIFY_REG(QSPIHandle.Instance->DCR, QUADSPI_DCR_CSHT, QSPI_CS_HIGH_TIME_6_CYCLE); + + return QSPI_OK; +} + +/** + * @brief Writes an amount of data to the QSPI memory. + * @param pData: Pointer to data to be written + * @param WriteAddr: Write start address + * @param Size: Size of data to write + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size) +{ + QSPI_CommandTypeDef s_command; + uint32_t end_addr, current_size, current_addr; + + /* Calculation of the size between the write address and the end of the page */ + current_size = N25Q512A_PAGE_SIZE - (WriteAddr % N25Q512A_PAGE_SIZE); + + /* Check if the size of the data is less than the remaining place in the page */ + if (current_size > Size) + { + current_size = Size; + } + + /* Initialize the address variables */ + current_addr = WriteAddr; + end_addr = WriteAddr + Size; + + /* Initialize the program command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = QUAD_IN_FAST_PROG_CMD; + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Perform the write page by page */ + do + { + s_command.Address = current_addr; + s_command.NbData = current_size; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of program */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update the address and size variables for next page programming */ + current_addr += current_size; + pData += current_size; + current_size = ((current_addr + N25Q512A_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : N25Q512A_PAGE_SIZE; + } while (current_addr < end_addr); + + return QSPI_OK; +} + +/** + * @brief Erases the specified block of the QSPI memory. + * @param BlockAddress: Block address to erase + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = SUBSECTOR_ERASE_CMD; + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.Address = BlockAddress; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, N25Q512A_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Erases the entire QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_Erase_Chip(void) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the erase command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = BULK_ERASE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for end of erase */ + if (QSPI_AutoPollingMemReady(&QSPIHandle, N25Q512A_BULK_ERASE_MAX_TIME) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief Reads current status of the QSPI memory. + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetStatus(void) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg; + + /* Initialize the read flag status register command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_FLAG_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(&QSPIHandle, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Check the value of the register */ + if ((reg & (N25Q512A_FSR_PRERR | N25Q512A_FSR_VPPERR | N25Q512A_FSR_PGERR | N25Q512A_FSR_ERERR)) != 0) + { + return QSPI_ERROR; + } + else if ((reg & (N25Q512A_FSR_PGSUS | N25Q512A_FSR_ERSUS)) != 0) + { + return QSPI_SUSPENDED; + } + else if ((reg & N25Q512A_FSR_READY) != 0) + { + return QSPI_OK; + } + else + { + return QSPI_BUSY; + } +} + +/** + * @brief Return the configuration of the QSPI memory. + * @param pInfo: pointer on the configuration structure + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_GetInfo(QSPI_Info* pInfo) +{ + /* Configure the structure with the memory configuration */ + pInfo->FlashSize = N25Q512A_FLASH_SIZE; + pInfo->EraseSectorSize = N25Q512A_SUBSECTOR_SIZE; + pInfo->EraseSectorsNumber = (N25Q512A_FLASH_SIZE/N25Q512A_SUBSECTOR_SIZE); + pInfo->ProgPageSize = N25Q512A_PAGE_SIZE; + pInfo->ProgPagesNumber = (N25Q512A_FLASH_SIZE/N25Q512A_PAGE_SIZE); + + return QSPI_OK; +} + +/** + * @brief Configure the QSPI in memory-mapped mode + * @retval QSPI memory status + */ +uint8_t BSP_QSPI_EnableMemoryMappedMode(void) +{ + QSPI_CommandTypeDef s_command; + QSPI_MemoryMappedTypeDef s_mem_mapped_cfg; + + /* Configure the command for the read instruction */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = QUAD_OUT_FAST_READ_CMD; + s_command.AddressMode = QSPI_ADDRESS_1_LINE; + s_command.AddressSize = QSPI_ADDRESS_32_BITS; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_4_LINES; + s_command.DummyCycles = N25Q512A_DUMMY_CYCLES_READ_QUAD; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the memory mapped mode */ + s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE; + s_mem_mapped_cfg.TimeOutPeriod = 0; + + if (HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @} + */ + +/** @addtogroup STM32F769I_EVAL_QSPI_Private_Functions + * @{ + */ + +/** + * @brief QSPI MSP Initialization + * @param hqspi: QSPI handle + * @param Params + * This function configures the hardware resources used in this example: + * - Peripheral's clock enable + * - Peripheral's GPIO Configuration + * - NVIC configuration for QSPI interrupt + * @retval None + */ +__weak void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + GPIO_InitTypeDef gpio_init_structure; + + /*##-1- Enable peripherals and GPIO Clocks #################################*/ + /* Enable the QuadSPI memory interface clock */ + QSPI_CLK_ENABLE(); + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + /* Enable GPIO clocks */ + QSPI_CS_GPIO_CLK_ENABLE(); + QSPI_CLK_GPIO_CLK_ENABLE(); + QSPI_D0_GPIO_CLK_ENABLE(); + QSPI_D1_GPIO_CLK_ENABLE(); + QSPI_D2_GPIO_CLK_ENABLE(); + QSPI_D3_GPIO_CLK_ENABLE(); + + /*##-2- Configure peripheral GPIO ##########################################*/ + /* QSPI CS GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CS_PIN; + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = GPIO_AF10_QUADSPI; + HAL_GPIO_Init(QSPI_CS_GPIO_PORT, &gpio_init_structure); + + /* QSPI CLK GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_CLK_PIN; + gpio_init_structure.Pull = GPIO_NOPULL; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_CLK_GPIO_PORT, &gpio_init_structure); + + /* QSPI D0 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D0_PIN; + gpio_init_structure.Alternate = GPIO_AF10_QUADSPI; + HAL_GPIO_Init(QSPI_D0_GPIO_PORT, &gpio_init_structure); + + /* QSPI D1 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D1_PIN; + gpio_init_structure.Alternate = GPIO_AF10_QUADSPI; + HAL_GPIO_Init(QSPI_D1_GPIO_PORT, &gpio_init_structure); + + /* QSPI D2 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D2_PIN; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_D2_GPIO_PORT, &gpio_init_structure); + + /* QSPI D3 GPIO pin configuration */ + gpio_init_structure.Pin = QSPI_D3_PIN; + gpio_init_structure.Alternate = GPIO_AF9_QUADSPI; + HAL_GPIO_Init(QSPI_D3_GPIO_PORT, &gpio_init_structure); + + /*##-3- Configure the NVIC for QSPI #########################################*/ + /* NVIC configuration for QSPI interrupt */ + HAL_NVIC_SetPriority(QUADSPI_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(QUADSPI_IRQn); +} + +/** + * @brief QSPI MSP De-Initialization + * @param hqspi: QSPI handle + * @param Params + * This function frees the hardware resources used in this example: + * - Disable the Peripheral's clock + * - Revert GPIO and NVIC configuration to their default state + * @retval None + */ +__weak void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params) +{ + /*##-1- Disable the NVIC for QSPI ###########################################*/ + HAL_NVIC_DisableIRQ(QUADSPI_IRQn); + + /*##-2- Disable peripherals and GPIO Clocks ################################*/ + /* De-Configure QSPI pins */ + HAL_GPIO_DeInit(QSPI_CS_GPIO_PORT, QSPI_CS_PIN); + HAL_GPIO_DeInit(QSPI_CLK_GPIO_PORT, QSPI_CLK_PIN); + HAL_GPIO_DeInit(QSPI_D0_GPIO_PORT, QSPI_D0_PIN); + HAL_GPIO_DeInit(QSPI_D1_GPIO_PORT, QSPI_D1_PIN); + HAL_GPIO_DeInit(QSPI_D2_GPIO_PORT, QSPI_D2_PIN); + HAL_GPIO_DeInit(QSPI_D3_GPIO_PORT, QSPI_D3_PIN); + + /*##-3- Reset peripherals ##################################################*/ + /* Reset the QuadSPI memory interface */ + QSPI_FORCE_RESET(); + QSPI_RELEASE_RESET(); + + /* Disable the QuadSPI memory interface clock */ + QSPI_CLK_DISABLE(); +} + +/** + * @brief This function reset the QSPI memory. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the reset enable command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = RESET_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Send the reset memory command */ + s_command.Instruction = RESET_MEMORY_CMD; + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait the memory is ready */ + if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function set the QSPI memory in 4-byte address mode + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_EnterFourBytesAddress(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + + /* Initialize the command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = ENTER_4_BYTE_ADDR_MODE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Enable write operations */ + if (QSPI_WriteEnable(hqspi) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Send the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait the memory is ready */ + if (QSPI_AutoPollingMemReady(hqspi, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function configure the dummy cycles on memory side. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_DummyCyclesCfg(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + uint8_t reg; + + /* Initialize the read volatile configuration register command */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_VOL_CFG_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.NbData = 1; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + /* Configure the command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Reception of the data */ + if (HAL_QSPI_Receive(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Enable write operations */ + if (QSPI_WriteEnable(hqspi) != QSPI_OK) + { + return QSPI_ERROR; + } + + /* Update volatile configuration register (with new dummy cycles) */ + s_command.Instruction = WRITE_VOL_CFG_REG_CMD; + MODIFY_REG(reg, N25Q512A_VCR_NB_DUMMY, (N25Q512A_DUMMY_CYCLES_READ_QUAD << POSITION_VAL(N25Q512A_VCR_NB_DUMMY))); + + /* Configure the write volatile configuration register command */ + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Transmission of the data */ + if (HAL_QSPI_Transmit(hqspi, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function send a Write Enable and wait it is effective. + * @param hqspi: QSPI handle + * @retval None + */ +static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Enable write operations */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = WRITE_ENABLE_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_NONE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + if (HAL_QSPI_Command(hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + /* Configure automatic polling mode to wait for write enabling */ + s_config.Match = N25Q512A_SR_WREN; + s_config.Mask = N25Q512A_SR_WREN; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.DataMode = QSPI_DATA_1_LINE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} + +/** + * @brief This function read the SR of the memory and wait the EOP. + * @param hqspi: QSPI handle + * @param Timeout + * @retval None + */ +static uint8_t QSPI_AutoPollingMemReady(QSPI_HandleTypeDef *hqspi, uint32_t Timeout) +{ + QSPI_CommandTypeDef s_command; + QSPI_AutoPollingTypeDef s_config; + + /* Configure automatic polling mode to wait for memory ready */ + s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; + s_command.Instruction = READ_STATUS_REG_CMD; + s_command.AddressMode = QSPI_ADDRESS_NONE; + s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; + s_command.DataMode = QSPI_DATA_1_LINE; + s_command.DummyCycles = 0; + s_command.DdrMode = QSPI_DDR_MODE_DISABLE; + s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; + s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; + + s_config.Match = 0; + s_config.Mask = N25Q512A_SR_WIP; + s_config.MatchMode = QSPI_MATCH_MODE_AND; + s_config.StatusBytesSize = 1; + s_config.Interval = 0x10; + s_config.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE; + + if (HAL_QSPI_AutoPolling(hqspi, &s_command, &s_config, Timeout) != HAL_OK) + { + return QSPI_ERROR; + } + + return QSPI_OK; +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_qspi.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_qspi.h new file mode 100644 index 00000000..c661b830 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_qspi.h @@ -0,0 +1,168 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_qspi.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_eval_qspi.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_EVAL_QSPI_H +#define __STM32F769I_EVAL_QSPI_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" +#include "../Components/n25q512a/n25q512a.h" + +/** @addtogroup STM32F769I_EVAL_QSPI + * @{ + */ + + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup STM32F769I_EVAL_QSPI_Exported_Constants Exported Constants + * @{ + */ +/* QSPI Error codes */ +#define QSPI_OK ((uint8_t)0x00) +#define QSPI_ERROR ((uint8_t)0x01) +#define QSPI_BUSY ((uint8_t)0x02) +#define QSPI_NOT_SUPPORTED ((uint8_t)0x04) +#define QSPI_SUSPENDED ((uint8_t)0x08) + + +/* Definition for QSPI clock resources */ +#define QSPI_CLK_ENABLE() __HAL_RCC_QSPI_CLK_ENABLE() +#define QSPI_CLK_DISABLE() __HAL_RCC_QSPI_CLK_DISABLE() +#define QSPI_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_CLK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define QSPI_D0_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() +#define QSPI_D1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() +#define QSPI_D2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() +#define QSPI_D3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() + +#define QSPI_FORCE_RESET() __HAL_RCC_QSPI_FORCE_RESET() +#define QSPI_RELEASE_RESET() __HAL_RCC_QSPI_RELEASE_RESET() + +/* Definition for QSPI Pins */ +#define QSPI_CS_PIN GPIO_PIN_6 +#define QSPI_CS_GPIO_PORT GPIOB +#define QSPI_CLK_PIN GPIO_PIN_2 +#define QSPI_CLK_GPIO_PORT GPIOB +#define QSPI_D0_PIN GPIO_PIN_8 +#define QSPI_D0_GPIO_PORT GPIOF +#define QSPI_D1_PIN GPIO_PIN_9 +#define QSPI_D1_GPIO_PORT GPIOF +#define QSPI_D2_PIN GPIO_PIN_7 +#define QSPI_D2_GPIO_PORT GPIOF +#define QSPI_D3_PIN GPIO_PIN_6 +#define QSPI_D3_GPIO_PORT GPIOF + +/* N25Q512A13GSF40E Micron memory */ +/* Size of the flash */ +#define QSPI_FLASH_SIZE 25 /* Address bus width to access whole memory space */ +#define QSPI_PAGE_SIZE 256 + +/** + * @} + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup STM32F769I_EVAL_QSPI_Exported_Types Exported Types + * @{ + */ +/* QSPI Info */ +typedef struct { + uint32_t FlashSize; /*!< Size of the flash */ + uint32_t EraseSectorSize; /*!< Size of sectors for the erase operation */ + uint32_t EraseSectorsNumber; /*!< Number of sectors for the erase operation */ + uint32_t ProgPageSize; /*!< Size of pages for the program operation */ + uint32_t ProgPagesNumber; /*!< Number of pages for the program operation */ +} QSPI_Info; + +/** + * @} + */ + + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup STM32F769I_EVAL_QSPI_Exported_Functions + * @{ + */ +uint8_t BSP_QSPI_Init (void); +uint8_t BSP_QSPI_DeInit (void); +uint8_t BSP_QSPI_Read (uint8_t* pData, uint32_t ReadAddr, uint32_t Size); +uint8_t BSP_QSPI_Write (uint8_t* pData, uint32_t WriteAddr, uint32_t Size); +uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress); +uint8_t BSP_QSPI_Erase_Chip (void); +uint8_t BSP_QSPI_GetStatus (void); +uint8_t BSP_QSPI_GetInfo (QSPI_Info* pInfo); +uint8_t BSP_QSPI_EnableMemoryMappedMode(void); + +/* These functions can be modified in case the current settings + need to be changed for specific application needs */ +void BSP_QSPI_MspInit(QSPI_HandleTypeDef *hqspi, void *Params); +void BSP_QSPI_MspDeInit(QSPI_HandleTypeDef *hqspi, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_EVAL_QSPI_H */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sd.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sd.c new file mode 100644 index 00000000..96772b99 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sd.c @@ -0,0 +1,1027 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_sd.c + * @author MCD Application Team + * @brief This file includes the uSD card driver mounted on STM32F769I-EVAL + * evaluation boards. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the micro SD external cards mounted on STM32F769I-EVAL + evaluation board. + - This driver does not need a specific component driver for the micro SD device + to be included with. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the micro SD card using the BSP_SD_InitEx() function. This + function includes the MSP layer hardware resources initialization and the + SDIO interface configuration to interface with the external micro SD. It + also includes the micro SD initialization sequence for SDCard1 or SDCard2. + When BSP_SD_Init() is called, SDCard1 is by default initialized. + o To check the SD card presence you can use the function BSP_SD_IsDetectedEx() which + returns the detection status for SDCard1 or SDCard2. + the function BSP_SD_IsDetected() returns the detection status for SDCard1. + o If SD presence detection interrupt mode is desired, you must configure the + SD detection interrupt mode by calling the functions BSP_SD_ITConfig() for + SDCard1 or BSP_SD_ITConfigEx() for SDCard2 . The interrupt is generated as + an external interrupt whenever the micro SD card is plugged/unplugged + in/from the evaluation board. The SD detection is managed by MFX, so the + SD detection interrupt has to be treated by MFX_IRQOUT gpio pin IRQ handler. + o The function BSP_SD_GetCardInfo()/BSP_SD_GetCardInfoEx() are used to get + the micro SD card information which is stored in the structure + "HAL_SD_CardInfoTypedef". + + + Micro SD card operations + o The micro SD card can be accessed with read/write block(s) operations once + it is ready for access. The access, by default to SDCard1, can be performed whether + using the polling mode by calling the functions BSP_SD_ReadBlocks()/BSP_SD_WriteBlocks(), + or by DMA transfer using the functions BSP_SD_ReadBlocks_DMA()/BSP_SD_WriteBlocks_DMA(). + The access can be performed to SDCard1 or SDCard2 by calling BSP_SD_ReadBlocksEx(), + BSP_SD_WriteBlocksEx() or by calling BSP_SD_ReadBlocks_DMAEx()/BSP_SD_WriteBlocks_DMAEx(). + o The DMA transfer complete is used with interrupt mode. Once the SD transfer + is complete, the SD interrupt is handled using the function BSP_SDMMC1_IRQHandler() + when SDCard1 is used or BSP_SDMMC2_IRQHandler() when SDCard2 is used. + The DMA Tx/Rx transfer complete are handled using the functions + BSP_SDMMC1_DMA_Tx_IRQHandler(), BSP_SDMMC1_DMA_Rx_IRQHandler(), + BSP_SDMMC2_DMA_Tx_IRQHandler(), BSP_SDMMC2_DMA_Rx_IRQHandler(). The corresponding + user callbacks are implemented by the user at application level. + o The SD erase block(s) is performed using the functions BSP_SD_Erase()/BSP_SD_EraseEx() + with specifying the number of blocks to erase. + o The SD runtime status is returned when calling the function BSP_SD_GetCardState() + BSP_SD_GetCardStateEx(). + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f769i_eval.c +- stm32f7xx_hal_sd.c +- stm32f7xx_ll_sdmmc.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval_sd.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_SD STM32F769I_EVAL SD + * @{ + */ + + +/** @defgroup STM32F769I_EVAL_SD_Private_TypesDefinitions SD Private TypesDefinitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SD_Private_Defines SD Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SD_Private_Macros SD Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SD_Private_Variables SD Private Variables + * @{ + */ +SD_HandleTypeDef uSdHandle; +SD_HandleTypeDef uSdHandle2; +static uint8_t UseExtiModeDetection = 0; + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SD_Private_Functions_Prototypes SD Private Functions Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SD_Private_Functions SD Private Functions + * @{ + */ + +/** + * @brief Initializes the SD card device. + * @retval SD status + */ +uint8_t BSP_SD_Init(void) +{ + /* By default, initialize SDMMC1 */ + return BSP_SD_InitEx(SD_CARD1); +} + +/** + * @brief Initializes the SD card device. + * @param SdCard: SD card to be used, that should be SD_CARD1 or SD_CARD2 + * @retval SD status + */ +uint8_t BSP_SD_InitEx(uint32_t SdCard) +{ + uint8_t sd_state = MSD_OK; + + /* uSD device interface configuration */ + if(SdCard == SD_CARD1) + { + uSdHandle.Instance = SDMMC1; + uSdHandle.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + uSdHandle.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE; + uSdHandle.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; + uSdHandle.Init.BusWide = SDMMC_BUS_WIDE_1B; + uSdHandle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + uSdHandle.Init.ClockDiv = SDMMC_TRANSFER_CLK_DIV; + } + else + { + uSdHandle2.Instance = SDMMC2; + uSdHandle2.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + uSdHandle2.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE; + uSdHandle2.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; + uSdHandle2.Init.BusWide = SDMMC_BUS_WIDE_1B; + uSdHandle2.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + uSdHandle2.Init.ClockDiv = SDMMC_TRANSFER_CLK_DIV; + } + /* Initialize IO functionalities (MFX) used by SD detect pin */ + BSP_IO_Init(); + + /* Check if the SD card is plugged in the slot */ + if(SdCard == SD_CARD1) + { + BSP_IO_ConfigPin(SD1_DETECT_PIN, IO_MODE_INPUT_PU); + + if(BSP_SD_IsDetected() != SD_PRESENT) + { + return MSD_ERROR_SD_NOT_PRESENT; + } + + /* Msp SD initialization */ + BSP_SD_MspInit(&uSdHandle, NULL); + + /* HAL SD initialization */ + if(HAL_SD_Init(&uSdHandle) != HAL_OK) + { + sd_state = MSD_ERROR; + } + } + else + { + BSP_IO_ConfigPin(SD2_DETECT_PIN, IO_MODE_INPUT_PU); + + if(BSP_SD_IsDetectedEx(SD_CARD2) != SD_PRESENT) + { + return MSD_ERROR_SD_NOT_PRESENT; + } + /* Msp SD initialization */ + BSP_SD_MspInit(&uSdHandle2, NULL); + + /* HAL SD initialization */ + if(HAL_SD_Init(&uSdHandle2) != HAL_OK) + { + sd_state = MSD_ERROR; + } + } + + + /* Configure SD Bus width */ + if(sd_state == MSD_OK) + { + if(SdCard == SD_CARD1) + { + /* Enable wide operation */ + sd_state = HAL_SD_ConfigWideBusOperation(&uSdHandle, SDMMC_BUS_WIDE_4B); + } + else + { + /* Enable wide operation */ + sd_state = HAL_SD_ConfigWideBusOperation(&uSdHandle2, SDMMC_BUS_WIDE_4B); + } + if(sd_state != HAL_OK) + { + sd_state = MSD_ERROR; + } + else + { + sd_state = MSD_OK; + } + } + + return sd_state; +} + + +/** + * @brief DeInitializes the SD card device. + * @retval SD status + */ +uint8_t BSP_SD_DeInit(void) +{ + /* By default, DeInitialize SDMMC1 */ + return BSP_SD_DeInitEx(SD_CARD1); +} + +/** + * @brief DeInitializes the SD card device. + * @param SdCard: SD card to be used, that should be SD_CARD1 or SD_CARD2 + * @retval SD status + */ +uint8_t BSP_SD_DeInitEx(uint32_t SdCard) +{ + uint8_t sd_state = MSD_OK; + + /* Set back Mfx pin to INPUT mode in case it was in exti */ + UseExtiModeDetection = 0; + if(SdCard == SD_CARD1) + { + uSdHandle.Instance = SDMMC1; + /* HAL SD deinitialization */ + if(HAL_SD_DeInit(&uSdHandle) != HAL_OK) + { + sd_state = MSD_ERROR; + } + + /* Msp SD deinitialization */ + BSP_SD_MspDeInit(&uSdHandle, NULL); + BSP_IO_ConfigPin(SD1_DETECT_PIN, IO_MODE_INPUT_PU); + } + else + { + uSdHandle2.Instance = SDMMC2; + BSP_IO_ConfigPin(SD2_DETECT_PIN, IO_MODE_INPUT_PU); + + /* HAL SD deinitialization */ + if(HAL_SD_DeInit(&uSdHandle2) != HAL_OK) + { + sd_state = MSD_ERROR; + } + + /* Msp SD deinitialization */ + BSP_SD_MspDeInit(&uSdHandle2, NULL); + } + return sd_state; +} + +/** + * @brief Configures Interrupt mode for SD1 detection pin. + * @retval Returns 0 + */ +uint8_t BSP_SD_ITConfig(void) +{ + /* Configure Interrupt mode for SD1 detection pin */ + /* Note: disabling exti mode can be done calling BSP_SD_DeInit() */ + UseExtiModeDetection = 1; + BSP_SD_IsDetected(); + + return 0; +} + +/** + * @brief Configures Interrupt mode for SD detection pin. + * @param SdCard: SD card to be used, that should be SD_CARD1 or SD_CARD2 + * @retval Returns 0 + */ +uint8_t BSP_SD_ITConfigEx(uint32_t SdCard) +{ + /* Configure Interrupt mode for SD2 detection pin */ + /* Note: disabling exti mode can be done calling BSP_SD_DeInitEx(SD_CARD2) */ + UseExtiModeDetection = 1; + BSP_SD_IsDetectedEx(SdCard); + + return 0; +} + +/** + * @brief Detects if SD card is correctly plugged in the memory slot or not. + * @retval Returns if SD is detected or not + */ +uint8_t BSP_SD_IsDetected(void) +{ + return BSP_SD_IsDetectedEx(SD_CARD1); +} + +/** + * @brief Detects if SD card is correctly plugged in the memory slot or not. + * @param SdCard: SD card to be used, that should be SD_CARD1 or SD_CARD2 + * @retval Returns if SD is detected or not + */ +uint8_t BSP_SD_IsDetectedEx(uint32_t SdCard) +{ + __IO uint8_t status = SD_PRESENT; + + if(SdCard == SD_CARD1) + { + /* Check SD card detect pin */ + if((BSP_IO_ReadPin(SD1_DETECT_PIN)&SD1_DETECT_PIN) != SD1_DETECT_PIN) + { + if (UseExtiModeDetection) + { + BSP_IO_ConfigPin(SD1_DETECT_PIN, IO_MODE_IT_RISING_EDGE_PU); + } + } + else + { + status = SD_NOT_PRESENT; + if (UseExtiModeDetection) + { + BSP_IO_ConfigPin(SD1_DETECT_PIN, IO_MODE_IT_FALLING_EDGE_PU); + } + } + } + else + { + /* Check SD card detect pin */ + if((BSP_IO_ReadPin(SD2_DETECT_PIN)&SD2_DETECT_PIN) != SD2_DETECT_PIN) + { + if (UseExtiModeDetection) + { + BSP_IO_ConfigPin(SD2_DETECT_PIN, IO_MODE_IT_RISING_EDGE_PU); + } + } + else + { + status = SD_NOT_PRESENT; + if (UseExtiModeDetection) + { + BSP_IO_ConfigPin(SD2_DETECT_PIN, IO_MODE_IT_FALLING_EDGE_PU); + } + } + } + return status; +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @param Timeout: Timeout for read operation + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + return BSP_SD_ReadBlocksEx(SD_CARD1, pData, ReadAddr, NumOfBlocks, Timeout); +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in polling mode. + * @param SdCard: SD card to be used, that should be SD_CARD1 or SD_CARD2 + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @param Timeout: Timeout for read operation + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocksEx(uint32_t SdCard, uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + HAL_StatusTypeDef sd_state = HAL_OK; + + if(SdCard == SD_CARD1) + { + sd_state = HAL_SD_ReadBlocks(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks, Timeout); + } + else + { + sd_state = HAL_SD_ReadBlocks(&uSdHandle2, (uint8_t *)pData, ReadAddr, NumOfBlocks, Timeout); + } + + if( sd_state == HAL_OK) + { + return MSD_OK; + } + else + { + return MSD_ERROR; + } +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in polling mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @param Timeout: Timeout for write operation + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + return BSP_SD_WriteBlocksEx(SD_CARD1, pData, WriteAddr, NumOfBlocks, Timeout); +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in polling mode. + * @param SdCard: SD card to be used, that should be SD_CARD1 or SD_CARD2 + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @param Timeout: Timeout for write operation + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocksEx(uint32_t SdCard, uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout) +{ + HAL_StatusTypeDef sd_state = HAL_OK; + + if(SdCard == SD_CARD1) + { + sd_state = HAL_SD_WriteBlocks(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks, Timeout); + } + else + { + sd_state = HAL_SD_WriteBlocks(&uSdHandle2, (uint8_t *)pData, WriteAddr, NumOfBlocks, Timeout); + } + + if( sd_state == HAL_OK) + { + return MSD_OK; + } + else + { + return MSD_ERROR; + } +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in DMA mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks) +{ + return BSP_SD_ReadBlocks_DMAEx(SD_CARD1, pData, ReadAddr, NumOfBlocks); +} + +/** + * @brief Reads block(s) from a specified address in an SD card, in DMA mode. + * @param SdCard: SD card to be used, that should be SD_CARD1 or SD_CARD2 + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param ReadAddr: Address from where data is to be read + * @param NumOfBlocks: Number of SD blocks to read + * @retval SD status + */ +uint8_t BSP_SD_ReadBlocks_DMAEx(uint32_t SdCard, uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks) +{ + HAL_StatusTypeDef sd_state = HAL_OK; + + if(SdCard == SD_CARD1) + { + /* Read block(s) in DMA transfer mode */ + sd_state = HAL_SD_ReadBlocks_DMA(&uSdHandle, (uint8_t *)pData, ReadAddr, NumOfBlocks); + } + else + { + /* Read block(s) in DMA transfer mode */ + sd_state = HAL_SD_ReadBlocks_DMA(&uSdHandle2, (uint8_t *)pData, ReadAddr, NumOfBlocks); + } + + if( sd_state == HAL_OK) + { + return MSD_OK; + } + else + { + return MSD_ERROR; + } +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in DMA mode. + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks) +{ + return BSP_SD_WriteBlocks_DMAEx(SD_CARD1, pData, WriteAddr, NumOfBlocks); +} + +/** + * @brief Writes block(s) to a specified address in an SD card, in DMA mode. + * @param SdCard: SD card to be used, that should be SD_CARD1 or SD_CARD2 + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param NumOfBlocks: Number of SD blocks to write + * @retval SD status + */ +uint8_t BSP_SD_WriteBlocks_DMAEx(uint32_t SdCard, uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks) +{ + HAL_StatusTypeDef sd_state = HAL_OK; + + if(SdCard == SD_CARD1) + { + /* Write block(s) in DMA transfer mode */ + sd_state = HAL_SD_WriteBlocks_DMA(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks); + } + else + { + /* Write block(s) in DMA transfer mode */ + sd_state = HAL_SD_WriteBlocks_DMA(&uSdHandle2, (uint8_t *)pData, WriteAddr, NumOfBlocks); + } + + if( sd_state == HAL_OK) + { + return MSD_OK; + } + else + { + return MSD_ERROR; + } +} + +/** + * @brief Erases the specified memory area of the given SD card. + * @param StartAddr: Start byte address + * @param EndAddr: End byte address + * @retval SD status + */ +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr) +{ + return BSP_SD_EraseEx(SD_CARD1, StartAddr, EndAddr); +} + +/** + * @brief Erases the specified memory area of the given SD card. + * @param SdCard: SD card to be used, that should be SD_CARD1 or SD_CARD2 + * @param StartAddr: Start byte address + * @param EndAddr: End byte address + * @retval SD status + */ +uint8_t BSP_SD_EraseEx(uint32_t SdCard, uint32_t StartAddr, uint32_t EndAddr) +{ + HAL_StatusTypeDef sd_state = HAL_OK; + + if(SdCard == SD_CARD1) + { + sd_state = HAL_SD_Erase(&uSdHandle, StartAddr, EndAddr); + } + else + { + sd_state = HAL_SD_Erase(&uSdHandle2, StartAddr, EndAddr); + } + + if( sd_state == HAL_OK) + { + return MSD_OK; + } + else + { + return MSD_ERROR; + } +} + +/** + * @brief Initializes the SD MSP. + * @param hsd: SD handle + * @param Params + * @retval None + */ +__weak void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params) +{ + static DMA_HandleTypeDef dma_rx_handle; + static DMA_HandleTypeDef dma_tx_handle; + static DMA_HandleTypeDef dma_rx_handle2; + static DMA_HandleTypeDef dma_tx_handle2; + GPIO_InitTypeDef gpio_init_structure; + + /* Camera has to be powered down as some signals use same GPIOs between + * SD card and camera bus. Camera drives its signals to low impedance + * when powered ON. So the camera is powered off to let its signals + * in high impedance */ + + /* Camera power down sequence */ + BSP_IO_ConfigPin(RSTI_PIN, IO_MODE_OUTPUT); + BSP_IO_ConfigPin(XSDN_PIN, IO_MODE_OUTPUT); + /* De-assert the camera STANDBY pin (active high) */ + BSP_IO_WritePin(XSDN_PIN, BSP_IO_PIN_RESET); + /* Assert the camera RSTI pin (active low) */ + BSP_IO_WritePin(RSTI_PIN, BSP_IO_PIN_RESET); + if(hsd->Instance == SDMMC1) + { + /* Enable SDIO clock */ + __HAL_RCC_SDMMC1_CLK_ENABLE(); + + /* Enable DMA2 clocks */ + __DMAx_TxRx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF12_SDMMC1; + + /* GPIOC configuration: SD1_D0, SD1_D1, SD1_D2, SD1_D3 and SD1_CLK pins */ + gpio_init_structure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; + + HAL_GPIO_Init(GPIOC, &gpio_init_structure); + + /* GPIOD configuration: SD1_CMD pin */ + gpio_init_structure.Pin = GPIO_PIN_2; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* NVIC configuration for SDIO interrupts */ + HAL_NVIC_SetPriority(SDMMC1_IRQn, 0x0E, 0); + HAL_NVIC_EnableIRQ(SDMMC1_IRQn); + + dma_rx_handle.Init.Channel = SD1_DMAx_Rx_CHANNEL; + dma_rx_handle.Init.Direction = DMA_PERIPH_TO_MEMORY; + dma_rx_handle.Init.PeriphInc = DMA_PINC_DISABLE; + dma_rx_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_rx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_rx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_rx_handle.Init.Mode = DMA_PFCTRL; + dma_rx_handle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + dma_rx_handle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + dma_rx_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_rx_handle.Init.MemBurst = DMA_MBURST_INC4; + dma_rx_handle.Init.PeriphBurst = DMA_PBURST_INC4; + dma_rx_handle.Instance = SD1_DMAx_Rx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsd, hdmarx, dma_rx_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_rx_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_rx_handle); + + dma_tx_handle.Init.Channel = SD1_DMAx_Tx_CHANNEL; + dma_tx_handle.Init.Direction = DMA_MEMORY_TO_PERIPH; + dma_tx_handle.Init.PeriphInc = DMA_PINC_DISABLE; + dma_tx_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_tx_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_tx_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_tx_handle.Init.Mode = DMA_PFCTRL; + dma_tx_handle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + dma_tx_handle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + dma_tx_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_tx_handle.Init.MemBurst = DMA_MBURST_INC4; + dma_tx_handle.Init.PeriphBurst = DMA_PBURST_INC4; + dma_tx_handle.Instance = SD1_DMAx_Tx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsd, hdmatx, dma_tx_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_tx_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_tx_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD1_DMAx_Rx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SD1_DMAx_Rx_IRQn); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD1_DMAx_Tx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SD1_DMAx_Tx_IRQn); + } + else + { + /* Enable SDIO clock */ + __HAL_RCC_SDMMC2_CLK_ENABLE(); + + /* Enable DMA2 clocks */ + __DMAx_TxRx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_HIGH; + gpio_init_structure.Alternate = GPIO_AF10_SDMMC2; + + /* GPIOB configuration: SD2_D2 and SD2_D3 pins */ + gpio_init_structure.Pin = GPIO_PIN_3 | GPIO_PIN_4; + + HAL_GPIO_Init(GPIOB, &gpio_init_structure); + + /* GPIOD configuration: SD2_CLK and SD2_CMD pins */ + gpio_init_structure.Pin = GPIO_PIN_6 | GPIO_PIN_7; + gpio_init_structure.Alternate = GPIO_AF11_SDMMC2; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOG configuration: SD2_D0 and SD2_D1 pins */ + gpio_init_structure.Pin = GPIO_PIN_9 | GPIO_PIN_10; + + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + /* NVIC configuration for SDIO interrupts */ + HAL_NVIC_SetPriority(SDMMC2_IRQn, 0x0E, 0); + HAL_NVIC_EnableIRQ(SDMMC2_IRQn); + + + dma_rx_handle2.Init.Channel = SD2_DMAx_Rx_CHANNEL; + dma_rx_handle2.Init.Direction = DMA_PERIPH_TO_MEMORY; + dma_rx_handle2.Init.PeriphInc = DMA_PINC_DISABLE; + dma_rx_handle2.Init.MemInc = DMA_MINC_ENABLE; + dma_rx_handle2.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_rx_handle2.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + dma_rx_handle2.Init.Mode = DMA_PFCTRL; + dma_rx_handle2.Init.Priority = DMA_PRIORITY_VERY_HIGH; + dma_rx_handle2.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + dma_rx_handle2.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_rx_handle2.Init.MemBurst = DMA_MBURST_INC16; + dma_rx_handle2.Init.PeriphBurst = DMA_PBURST_INC4; + dma_rx_handle2.Instance = SD2_DMAx_Rx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsd, hdmarx, dma_rx_handle2); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_rx_handle2); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_rx_handle2); + + dma_tx_handle2.Init.Channel = SD2_DMAx_Tx_CHANNEL; + dma_tx_handle2.Init.Direction = DMA_MEMORY_TO_PERIPH; + dma_tx_handle2.Init.PeriphInc = DMA_PINC_DISABLE; + dma_tx_handle2.Init.MemInc = DMA_MINC_ENABLE; + dma_tx_handle2.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_tx_handle2.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + dma_tx_handle2.Init.Mode = DMA_PFCTRL; + dma_tx_handle2.Init.Priority = DMA_PRIORITY_VERY_HIGH; + dma_tx_handle2.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + dma_tx_handle2.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_tx_handle2.Init.MemBurst = DMA_MBURST_INC16; + dma_tx_handle2.Init.PeriphBurst = DMA_PBURST_INC4; + dma_tx_handle2.Instance = SD2_DMAx_Tx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsd, hdmatx, dma_tx_handle2); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_tx_handle2); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_tx_handle2); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD2_DMAx_Rx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SD2_DMAx_Rx_IRQn); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD2_DMAx_Tx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SD2_DMAx_Tx_IRQn); + } +} + +/** + * @brief DeInitializes the SD MSP. + * @param hsd: SD handle + * @param Params + * @retval None + */ +__weak void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params) +{ + static DMA_HandleTypeDef dma_rx_handle; + static DMA_HandleTypeDef dma_tx_handle; + static DMA_HandleTypeDef dma_rx_handle2; + static DMA_HandleTypeDef dma_tx_handle2; + + if(hsd->Instance == SDMMC1) + { + /* Disable NVIC for DMA transfer complete interrupts */ + HAL_NVIC_DisableIRQ(SD1_DMAx_Rx_IRQn); + HAL_NVIC_DisableIRQ(SD1_DMAx_Tx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_rx_handle.Instance = SD1_DMAx_Rx_STREAM; + HAL_DMA_DeInit(&dma_rx_handle); + + /* Deinitialize the stream for new transfer */ + dma_tx_handle.Instance = SD1_DMAx_Tx_STREAM; + HAL_DMA_DeInit(&dma_tx_handle); + + /* Disable NVIC for SDIO interrupts */ + HAL_NVIC_DisableIRQ(SDMMC1_IRQn); + + /* DeInit GPIO pins can be done in the application + (by surcharging this __weak function) */ + + /* Disable SDMMC1 clock */ + __HAL_RCC_SDMMC1_CLK_DISABLE(); + } + else + { /* Disable NVIC for DMA transfer complete interrupts */ + HAL_NVIC_DisableIRQ(SD2_DMAx_Rx_IRQn); + HAL_NVIC_DisableIRQ(SD2_DMAx_Tx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_rx_handle2.Instance = SD2_DMAx_Rx_STREAM; + HAL_DMA_DeInit(&dma_rx_handle2); + + /* Deinitialize the stream for new transfer */ + dma_tx_handle2.Instance = SD2_DMAx_Tx_STREAM; + HAL_DMA_DeInit(&dma_tx_handle2); + + /* Disable NVIC for SDIO interrupts */ + HAL_NVIC_DisableIRQ(SDMMC2_IRQn); + + /* DeInit GPIO pins can be done in the application + (by surcharging this __weak function) */ + + /* Disable SDMMC2 clock */ + __HAL_RCC_SDMMC2_CLK_DISABLE(); + } + /* GPIO pins clock and DMA clocks can be shut down in the application + by surcharging this __weak function */ +} + +/** + * @brief Gets the current SD card data status. + * @retval Data transfer state. + * This value can be one of the following values: + * @arg SD_TRANSFER_OK: No data transfer is acting + * @arg SD_TRANSFER_BUSY: Data transfer is acting + */ +uint8_t BSP_SD_GetCardState(void) +{ + return BSP_SD_GetCardStateEx(SD_CARD1); +} + +/** + * @brief Gets the current SD card data status. + * @param SdCard: SD_CARD1 or SD_CARD2 + * @retval Data transfer state. + * This value can be one of the following values: + * @arg SD_TRANSFER_OK: No data transfer is acting + * @arg SD_TRANSFER_BUSY: Data transfer is acting + */ +uint8_t BSP_SD_GetCardStateEx(uint32_t SdCard) +{ + if(SdCard == SD_CARD1) + { + return((HAL_SD_GetCardState(&uSdHandle) == HAL_SD_CARD_TRANSFER ) ? SD_TRANSFER_OK : SD_TRANSFER_BUSY); + } + else + { + return((HAL_SD_GetCardState(&uSdHandle2) == HAL_SD_CARD_TRANSFER ) ? SD_TRANSFER_OK : SD_TRANSFER_BUSY); + } +} + +/** + * @brief Get SD information about specific SD card. + * @param CardInfo: Pointer to HAL_SD_CardInfoTypedef structure + * @retval None + */ +void BSP_SD_GetCardInfo(BSP_SD_CardInfo *CardInfo) +{ + BSP_SD_GetCardInfoEx(SD_CARD1, CardInfo); +} + +/** + * @brief Get SD information about specific SD card. + * @param SdCard: SD card to be used, that should be SD_CARD1 or SD_CARD2 + * @param CardInfo: Pointer to HAL_SD_CardInfoTypedef structure + * @retval None + */ +void BSP_SD_GetCardInfoEx(uint32_t SdCard, BSP_SD_CardInfo *CardInfo) +{ + /* Get SD card Information */ + if(SdCard == SD_CARD1) + { + HAL_SD_GetCardInfo(&uSdHandle, CardInfo); + } + else + { + HAL_SD_GetCardInfo(&uSdHandle2, CardInfo); + } +} + +/** + * @brief SD Abort callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_AbortCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_AbortCallback((hsd == &uSdHandle) ? SD_CARD1 : SD_CARD2); +} + +/** + * @brief Tx Transfer completed callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_WriteCpltCallback((hsd == &uSdHandle) ? SD_CARD1 : SD_CARD2); +} + +/** + * @brief Rx Transfer completed callbacks + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) +{ + BSP_SD_ReadCpltCallback((hsd == &uSdHandle) ? SD_CARD1 : SD_CARD2); +} + +/** + * @brief BSP SD Abort callbacks + * @param SdCard: SD_CARD1 or SD_CARD2 + * @retval None + */ +__weak void BSP_SD_AbortCallback(uint32_t SdCard) +{ + +} + +/** + * @brief BSP Tx Transfer completed callbacks + * @param SdCard: SD_CARD1 or SD_CARD2 + * @retval None + */ +__weak void BSP_SD_WriteCpltCallback(uint32_t SdCard) +{ + +} + +/** + * @brief BSP Rx Transfer completed callbacks + * @param SdCard: SD_CARD1 or SD_CARD2 + * @retval None + */ +__weak void BSP_SD_ReadCpltCallback(uint32_t SdCard) +{ + +} +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sd.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sd.h new file mode 100644 index 00000000..f36b8c0a --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sd.h @@ -0,0 +1,187 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_sd.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_eval_sd.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_EVAL_SD_H +#define __STM32F769I_EVAL_SD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" +#include "stm32f769i_eval_io.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @addtogroup STM32F769I_EVAL_SD + * @{ + */ + +/** @defgroup STM32F769I_EVAL_SD_Exported_Types SD Exported Types + * @{ + */ + +/** + * @brief SD Card information structure + */ +#define BSP_SD_CardInfo HAL_SD_CardInfoTypeDef +/** + * @} + */ + +/** + * @brief SD status structure definition + */ +#define MSD_OK ((uint8_t)0x00) +#define MSD_ERROR ((uint8_t)0x01) +#define MSD_ERROR_SD_NOT_PRESENT ((uint8_t)0x02) + +/** + * @brief SD transfer state definition + */ +#define SD_TRANSFER_OK ((uint8_t)0x00) +#define SD_TRANSFER_BUSY ((uint8_t)0x01) + +/** @defgroup STM32F769I_EVAL_SD_Exported_Constants SD Exported Constants + * @{ + */ +#define SD_PRESENT ((uint8_t)0x01) +#define SD_NOT_PRESENT ((uint8_t)0x00) + +#define SD_CARD1 ((uint32_t)0x00) +#define SD_CARD2 ((uint32_t)0x01) + +#define SD_DATATIMEOUT ((uint32_t)100000000) + +/* DMA definitions for SD DMA transfer */ +#define __DMAx_TxRx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define SD1_DMAx_Tx_CHANNEL DMA_CHANNEL_4 +#define SD1_DMAx_Rx_CHANNEL DMA_CHANNEL_4 +#define SD1_DMAx_Tx_STREAM DMA2_Stream6 +#define SD1_DMAx_Rx_STREAM DMA2_Stream3 +#define SD1_DMAx_Tx_IRQn DMA2_Stream6_IRQn +#define SD1_DMAx_Rx_IRQn DMA2_Stream3_IRQn +#define BSP_SDMMC1_DMA_Tx_IRQHandler DMA2_Stream6_IRQHandler +#define BSP_SDMMC1_DMA_Rx_IRQHandler DMA2_Stream3_IRQHandler +#define BSP_SDMMC1_IRQHandler SDMMC1_IRQHandler + +#define SD2_DMAx_Tx_CHANNEL DMA_CHANNEL_11 +#define SD2_DMAx_Rx_CHANNEL DMA_CHANNEL_11 +#define SD2_DMAx_Tx_STREAM DMA2_Stream5 +#define SD2_DMAx_Rx_STREAM DMA2_Stream0 +#define SD2_DMAx_Tx_IRQn DMA2_Stream5_IRQn +#define SD2_DMAx_Rx_IRQn DMA2_Stream0_IRQn +#define BSP_SDMMC2_DMA_Tx_IRQHandler DMA2_Stream5_IRQHandler +#define BSP_SDMMC2_DMA_Rx_IRQHandler DMA2_Stream0_IRQHandler +#define BSP_SDMMC2_IRQHandler SDMMC2_IRQHandler + +#define SD_DetectIRQHandler() HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_8) +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SD_Exported_Macro SD Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SD_Exported_Functions SD Exported Functions + * @{ + */ +uint8_t BSP_SD_Init(void); +uint8_t BSP_SD_InitEx(uint32_t SdCard); +uint8_t BSP_SD_DeInit(void); +uint8_t BSP_SD_DeInitEx(uint32_t SdCard); +uint8_t BSP_SD_ITConfig(void); +uint8_t BSP_SD_ITConfigEx(uint32_t SdCard); +uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_ReadBlocksEx(uint32_t SdCard, uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_WriteBlocks(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_WriteBlocksEx(uint32_t SdCard, uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks, uint32_t Timeout); +uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks); +uint8_t BSP_SD_ReadBlocks_DMAEx(uint32_t SdCard, uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks); +uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks); +uint8_t BSP_SD_WriteBlocks_DMAEx(uint32_t SdCard, uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks); +uint8_t BSP_SD_Erase(uint32_t StartAddr, uint32_t EndAddr); +uint8_t BSP_SD_EraseEx(uint32_t SdCard, uint32_t StartAddr, uint32_t EndAddr); +uint8_t BSP_SD_GetCardState(void); +uint8_t BSP_SD_GetCardStateEx(uint32_t SdCard); +void BSP_SD_GetCardInfo(BSP_SD_CardInfo *CardInfo); +void BSP_SD_GetCardInfoEx(uint32_t SdCard, BSP_SD_CardInfo *CardInfo); +uint8_t BSP_SD_IsDetected(void); +uint8_t BSP_SD_IsDetectedEx(uint32_t SdCard); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_SD_MspInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_MspDeInit(SD_HandleTypeDef *hsd, void *Params); +void BSP_SD_AbortCallback(uint32_t SdCard); +void BSP_SD_WriteCpltCallback(uint32_t SdCard); +void BSP_SD_ReadCpltCallback(uint32_t SdCard); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_EVAL_SD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sdram.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sdram.c new file mode 100644 index 00000000..f76cf475 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sdram.c @@ -0,0 +1,503 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_sdram.c + * @author MCD Application Team + * @brief This file includes the SDRAM driver for the MT48LC4M32B2B5-7 memory + * device mounted on STM32F769I-EVAL evaluation boards. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the MT48LC4M32B2B5-7 SDRAM external memory mounted + on STM32F769I-EVAL evaluation board. + - This driver does not need a specific component driver for the SDRAM device + to be included with. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the SDRAM external memory using the BSP_SDRAM_Init() function. This + function includes the MSP layer hardware resources initialization and the + FMC controller configuration to interface with the external SDRAM memory. + o It contains the SDRAM initialization sequence to program the SDRAM external + device using the function BSP_SDRAM_Initialization_sequence(). Note that this + sequence is standard for all SDRAM devices, but can include some differences + from a device to another. If it is the case, the right sequence should be + implemented separately. + + + SDRAM read/write operations + o SDRAM external memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_SDRAM_ReadData()/BSP_SDRAM_WriteData(), or by DMA transfer using the functions + BSP_SDRAM_ReadData_DMA()/BSP_SDRAM_WriteData_DMA(). + o The AHB access is performed with 32-bit width transaction, the DMA transfer + configuration is fixed at single (no burst) word transfer (see the + SDRAM_MspInit() static function). + o User can implement his own functions for read/write access with his desired + configurations. + o If interrupt mode is used for DMA transfer, the function BSP_SDRAM_DMA_IRQHandler() + is called in IRQ handler file, to serve the generated interrupt once the DMA + transfer is complete. + o You can send a command to the SDRAM device in runtime using the function + BSP_SDRAM_Sendcmd(), and giving the desired command as parameter chosen between + the predefined commands of the "FMC_SDRAM_CommandTypeDef" structure. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_sdram.c +- stm32f7xx_ll_fmc.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval_sdram.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_SDRAM STM32F769I_EVAL SDRAM + * @{ + */ + +/** @defgroup STM32F769I_EVAL_SDRAM_Private_Types_Definitions SDRAM Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SDRAM_Private_Defines SDRAM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SDRAM_Private_Macros SDRAM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SDRAM_Private_Variables SDRAM Private Variables + * @{ + */ +SDRAM_HandleTypeDef sdramHandle; +static FMC_SDRAM_TimingTypeDef Timing; +static FMC_SDRAM_CommandTypeDef Command; +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SDRAM_Private_Functions_Prototypes SDRAM Private Functions Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SDRAM_Private_Functions SDRAM Private Functions + * @{ + */ + +/** + * @brief Initializes the SDRAM device. + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_Init(void) +{ + static uint8_t sdramstatus = SDRAM_ERROR; + /* SDRAM device configuration */ + sdramHandle.Instance = FMC_SDRAM_DEVICE; + + /* Timing configuration for 100Mhz as SDRAM clock frequency (System clock is up to 200Mhz) */ + Timing.LoadToActiveDelay = 2; + Timing.ExitSelfRefreshDelay = 7; + Timing.SelfRefreshTime = 4; + Timing.RowCycleDelay = 7; + Timing.WriteRecoveryTime = 2; + Timing.RPDelay = 2; + Timing.RCDDelay = 2; + + sdramHandle.Init.SDBank = FMC_SDRAM_BANK1; + sdramHandle.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9; + sdramHandle.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12; + sdramHandle.Init.MemoryDataWidth = SDRAM_MEMORY_WIDTH; + sdramHandle.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; + sdramHandle.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3; + sdramHandle.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; + sdramHandle.Init.SDClockPeriod = SDCLOCK_PERIOD; + sdramHandle.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE; + sdramHandle.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; + + /* SDRAM controller initialization */ + + BSP_SDRAM_MspInit(&sdramHandle, NULL); /* __weak function can be rewritten by the application */ + + if(HAL_SDRAM_Init(&sdramHandle, &Timing) != HAL_OK) + { + sdramstatus = SDRAM_ERROR; + } + else + { + sdramstatus = SDRAM_OK; + } + + /* SDRAM initialization sequence */ + BSP_SDRAM_Initialization_sequence(REFRESH_COUNT); + + return sdramstatus; +} + +/** + * @brief DeInitializes the SDRAM device. + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_DeInit(void) +{ + static uint8_t sdramstatus = SDRAM_ERROR; + /* SDRAM device de-initialization */ + sdramHandle.Instance = FMC_SDRAM_DEVICE; + + if(HAL_SDRAM_DeInit(&sdramHandle) != HAL_OK) + { + sdramstatus = SDRAM_ERROR; + } + else + { + sdramstatus = SDRAM_OK; + } + + /* SDRAM controller de-initialization */ + BSP_SDRAM_MspDeInit(&sdramHandle, NULL); + + return sdramstatus; +} + +/** + * @brief Programs the SDRAM device. + * @param RefreshCount: SDRAM refresh counter value + * @retval None + */ +void BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount) +{ + __IO uint32_t tmpmrd = 0; + + /* Step 1: Configure a clock configuration enable command */ + Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 2: Insert 100 us minimum delay */ + /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */ + HAL_Delay(1); + + /* Step 3: Configure a PALL (precharge all) command */ + Command.CommandMode = FMC_SDRAM_CMD_PALL; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 4: Configure an Auto Refresh command */ + Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 8; + Command.ModeRegisterDefinition = 0; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 5: Program the external memory mode register */ + tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 |\ + SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |\ + SDRAM_MODEREG_CAS_LATENCY_3 |\ + SDRAM_MODEREG_OPERATING_MODE_STANDARD |\ + SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; + + Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; + Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; + Command.AutoRefreshNumber = 1; + Command.ModeRegisterDefinition = tmpmrd; + + /* Send the command */ + HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT); + + /* Step 6: Set the refresh rate counter */ + /* Set the device refresh rate */ + HAL_SDRAM_ProgramRefreshRate(&sdramHandle, RefreshCount); +} + +/** + * @brief Reads an amount of data from the SDRAM memory in polling mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_ReadData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Read_32b(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Reads an amount of data from the SDRAM memory in DMA mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_ReadData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Read_DMA(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Writes an amount of data to the SDRAM memory in polling mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_WriteData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Write_32b(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Writes an amount of data to the SDRAM memory in DMA mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_WriteData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize) +{ + if(HAL_SDRAM_Write_DMA(&sdramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Sends command to the SDRAM bank. + * @param SdramCmd: Pointer to SDRAM command structure + * @retval SDRAM status + */ +uint8_t BSP_SDRAM_Sendcmd(FMC_SDRAM_CommandTypeDef *SdramCmd) +{ + if(HAL_SDRAM_SendCommand(&sdramHandle, SdramCmd, SDRAM_TIMEOUT) != HAL_OK) + { + return SDRAM_ERROR; + } + else + { + return SDRAM_OK; + } +} + +/** + * @brief Initializes SDRAM MSP. + * @param hsdram: SDRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable FMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + + /* Enable chosen DMAx clock */ + __DMAx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = GPIO_AF12_FMC; + + /* GPIOD configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8| GPIO_PIN_9 | GPIO_PIN_10 |\ + GPIO_PIN_14 | GPIO_PIN_15; + + + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOE configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7| GPIO_PIN_8 | GPIO_PIN_9 |\ + GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\ + GPIO_PIN_15; + + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOF configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\ + GPIO_PIN_15; + + HAL_GPIO_Init(GPIOF, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4| GPIO_PIN_5 | GPIO_PIN_8 |\ + GPIO_PIN_15; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + /* GPIOH configuration */ + gpio_init_structure.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_9 |\ + GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |\ + GPIO_PIN_15; + HAL_GPIO_Init(GPIOH, &gpio_init_structure); + + /* GPIOI configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_9 | GPIO_PIN_10; + HAL_GPIO_Init(GPIOI, &gpio_init_structure); + + /* Configure common DMA parameters */ + dma_handle.Init.Channel = SDRAM_DMAx_CHANNEL; + dma_handle.Init.Direction = DMA_MEMORY_TO_MEMORY; + dma_handle.Init.PeriphInc = DMA_PINC_ENABLE; + dma_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + dma_handle.Init.Mode = DMA_NORMAL; + dma_handle.Init.Priority = DMA_PRIORITY_HIGH; + dma_handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + dma_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_handle.Init.MemBurst = DMA_MBURST_SINGLE; + dma_handle.Init.PeriphBurst = DMA_PBURST_SINGLE; + + dma_handle.Instance = SDRAM_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsdram, hdma, dma_handle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&dma_handle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&dma_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SDRAM_DMAx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SDRAM_DMAx_IRQn); +} + +/** + * @brief DeInitializes SDRAM MSP. + * @param hsdram: SDRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SDRAM_MspDeInit(SDRAM_HandleTypeDef *hsdram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + + /* Disable NVIC configuration for DMA interrupt */ + HAL_NVIC_DisableIRQ(SDRAM_DMAx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_handle.Instance = SDRAM_DMAx_STREAM; + HAL_DMA_DeInit(&dma_handle); + + /* GPIO pins clock, FMC clock and DMA clock can be shut down in the applications + by surcharging this __weak function */ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sdram.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sdram.h new file mode 100644 index 00000000..6ca06ff6 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sdram.h @@ -0,0 +1,163 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_sdram.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_eval_sdram.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_EVAL_SDRAM_H +#define __STM32F769I_EVAL_SDRAM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @addtogroup STM32F769I_EVAL_SDRAM + * @{ + */ + +/** @defgroup STM32F769I_EVAL_SDRAM_Exported_Types SDRAM Exported Types + * @{ + */ + +/** + * @brief SDRAM status structure definition + */ +#define SDRAM_OK ((uint8_t)0x00) +#define SDRAM_ERROR ((uint8_t)0x01) + +/** @defgroup STM32F769I_EVAL_SDRAM_Exported_Constants SDRAM Exported Constants + * @{ + */ +#define SDRAM_DEVICE_ADDR ((uint32_t)0xC0000000) +#define SDRAM_DEVICE_SIZE ((uint32_t)0x2000000) /* SDRAM device size in MBytes */ + +/* #define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_8 */ +/* #define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_16 */ +#define SDRAM_MEMORY_WIDTH FMC_SDRAM_MEM_BUS_WIDTH_32 + +#define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_2 +/* #define SDCLOCK_PERIOD FMC_SDRAM_CLOCK_PERIOD_3 */ + +#define REFRESH_COUNT ((uint32_t)0x0603) /* SDRAM refresh counter (100Mhz SD clock) */ + +#define SDRAM_TIMEOUT ((uint32_t)0xFFFF) + +/* DMA definitions for SDRAM DMA transfer */ +#define __DMAx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define __DMAx_CLK_DISABLE __HAL_RCC_DMA2_CLK_DISABLE +#define SDRAM_DMAx_CHANNEL DMA_CHANNEL_0 +#define SDRAM_DMAx_STREAM DMA2_Stream0 +#define SDRAM_DMAx_IRQn DMA2_Stream0_IRQn +#define BSP_SDRAM_DMA_IRQHandler DMA2_Stream0_IRQHandler +/** + * @} + */ + +/** + * @brief FMC SDRAM Mode definition register defines + */ +#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) +#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) +#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) +#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) +#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) +#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) +#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SDRAM_Exported_Macro SDRAM Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SDRAM_Exported_Functions SDRAM Exported Functions + * @{ + */ +uint8_t BSP_SDRAM_Init(void); +uint8_t BSP_SDRAM_DeInit(void); +void BSP_SDRAM_Initialization_sequence(uint32_t RefreshCount); +uint8_t BSP_SDRAM_ReadData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_ReadData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_WriteData(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_WriteData_DMA(uint32_t uwStartAddress, uint32_t *pData, uint32_t uwDataSize); +uint8_t BSP_SDRAM_Sendcmd(FMC_SDRAM_CommandTypeDef *SdramCmd); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram, void *Params); +void BSP_SDRAM_MspDeInit(SDRAM_HandleTypeDef *hsdram, void *Params); + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_EVAL_SDRAM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sram.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sram.c new file mode 100644 index 00000000..ed7b6eab --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sram.c @@ -0,0 +1,402 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_sram.c + * @author MCD Application Team + * @brief This file includes the SRAM driver for the IS61WV102416BLL-10M memory + * device mounted on STM32F769I-EVAL evaluation boards. + @verbatim + How To use this driver: + ----------------------- + - This driver is used to drive the IS61WV102416BLL-10M SRAM external memory mounted + on STM32F769I-EVAL evaluation board. + - This driver does not need a specific component driver for the SRAM device + to be included with. + + Driver description: + ------------------ + + Initialization steps: + o Initialize the SRAM external memory using the BSP_SRAM_Init() function. This + function includes the MSP layer hardware resources initialization and the + FMC controller configuration to interface with the external SRAM memory. + + + SRAM read/write operations + o SRAM external memory can be accessed with read/write operations once it is + initialized. + Read/write operation can be performed with AHB access using the functions + BSP_SRAM_ReadData()/BSP_SRAM_WriteData(), or by DMA transfer using the functions + BSP_SRAM_ReadData_DMA()/BSP_SRAM_WriteData_DMA(). + o The AHB access is performed with 16-bit width transaction, the DMA transfer + configuration is fixed at single (no burst) halfword transfer + (see the SRAM_MspInit() static function). + o User can implement his own functions for read/write access with his desired + configurations. + o If interrupt mode is used for DMA transfer, the function BSP_SRAM_DMA_IRQHandler() + is called in IRQ handler file, to serve the generated interrupt once the DMA + transfer is complete. + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Dependencies +- stm32f7xx_hal_sram.c +- stm32f7xx_ll_fmc.c +- stm32f7xx_hal_dma.c +- stm32f7xx_hal_gpio.c +- stm32f7xx_hal_cortex.c +- stm32f7xx_hal_rcc_ex.h +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval_sram.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_SRAM STM32F769I_EVAL SRAM + * @{ + */ + +/** @defgroup STM32F769I_EVAL_SRAM_Private_Types_Definitions SRAM Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SRAM_Private_Defines EVAL SRAM Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SRAM_Private_Macros SRAM Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SRAM_Private_Variables SRAM Private Variables + * @{ + */ +SRAM_HandleTypeDef sramHandle; +static FMC_NORSRAM_TimingTypeDef Timing; +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SRAM_Private_Functions_Prototypes SRAM Private Functions Prototypes + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SRAM_Private_Functions SRAM Private Functions + * @{ + */ + +/** + * @brief Initializes the SRAM device. + * @retval SRAM status + */ +uint8_t BSP_SRAM_Init(void) +{ + static uint8_t sram_status = SRAM_ERROR; + /* SRAM device configuration */ + sramHandle.Instance = FMC_NORSRAM_DEVICE; + sramHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + /* SRAM device configuration */ + /* Timing configuration derived from system clock (up to 216Mhz) + for 108Mhz as SRAM clock frequency */ + Timing.AddressSetupTime = 2; + Timing.AddressHoldTime = 1; + Timing.DataSetupTime = 2; + Timing.BusTurnAroundDuration = 1; + Timing.CLKDivision = 2; + Timing.DataLatency = 2; + Timing.AccessMode = FMC_ACCESS_MODE_A; + + sramHandle.Init.NSBank = FMC_NORSRAM_BANK3; + sramHandle.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; + sramHandle.Init.MemoryType = FMC_MEMORY_TYPE_SRAM; + sramHandle.Init.MemoryDataWidth = SRAM_MEMORY_WIDTH; + sramHandle.Init.BurstAccessMode = SRAM_BURSTACCESS; + sramHandle.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; + sramHandle.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; + sramHandle.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; + sramHandle.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE; + sramHandle.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; + sramHandle.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE; + sramHandle.Init.WriteBurst = SRAM_WRITEBURST; + sramHandle.Init.ContinuousClock = CONTINUOUSCLOCK_FEATURE; + + /* SRAM controller initialization */ + BSP_SRAM_MspInit(&sramHandle, NULL); /* __weak function can be rewritten by the application */ + if(HAL_SRAM_Init(&sramHandle, &Timing, &Timing) != HAL_OK) + { + sram_status = SRAM_ERROR; + } + else + { + sram_status = SRAM_OK; + } + return sram_status; +} + +/** + * @brief DeInitializes the SRAM device. + * @retval SRAM status + */ +uint8_t BSP_SRAM_DeInit(void) +{ + static uint8_t sram_status = SRAM_ERROR; + /* SRAM device de-initialization */ + sramHandle.Instance = FMC_NORSRAM_DEVICE; + sramHandle.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + + if(HAL_SRAM_DeInit(&sramHandle) != HAL_OK) + { + sram_status = SRAM_ERROR; + } + else + { + sram_status = SRAM_OK; + } + + /* SRAM controller de-initialization */ + BSP_SRAM_MspDeInit(&sramHandle, NULL); + + return sram_status; +} + +/** + * @brief Reads an amount of data from the SRAM device in polling mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SRAM status + */ +uint8_t BSP_SRAM_ReadData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Read_16b(&sramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SRAM_ERROR; + } + else + { + return SRAM_OK; + } +} + +/** + * @brief Reads an amount of data from the SRAM device in DMA mode. + * @param uwStartAddress: Read start address + * @param pData: Pointer to data to be read + * @param uwDataSize: Size of read data from the memory + * @retval SRAM status + */ +uint8_t BSP_SRAM_ReadData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Read_DMA(&sramHandle, (uint32_t *)uwStartAddress, (uint32_t *)pData, uwDataSize) != HAL_OK) + { + return SRAM_ERROR; + } + else + { + return SRAM_OK; + } +} + +/** + * @brief Writes an amount of data from the SRAM device in polling mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SRAM status + */ +uint8_t BSP_SRAM_WriteData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Write_16b(&sramHandle, (uint32_t *)uwStartAddress, pData, uwDataSize) != HAL_OK) + { + return SRAM_ERROR; + } + else + { + return SRAM_OK; + } +} + +/** + * @brief Writes an amount of data from the SRAM device in DMA mode. + * @param uwStartAddress: Write start address + * @param pData: Pointer to data to be written + * @param uwDataSize: Size of written data from the memory + * @retval SRAM status + */ +uint8_t BSP_SRAM_WriteData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize) +{ + if(HAL_SRAM_Write_DMA(&sramHandle, (uint32_t *)uwStartAddress, (uint32_t *)pData, uwDataSize) != HAL_OK) + { + return SRAM_ERROR; + } + else + { + return SRAM_OK; + } +} + +/** + * @brief Initializes SRAM MSP. + * @param hsram: SRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SRAM_MspInit(SRAM_HandleTypeDef *hsram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + GPIO_InitTypeDef gpio_init_structure; + + /* Enable FMC clock */ + __HAL_RCC_FMC_CLK_ENABLE(); + + /* Enable chosen DMAx clock */ + __SRAM_DMAx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + + /* Common GPIO configuration */ + gpio_init_structure.Mode = GPIO_MODE_AF_PP; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + gpio_init_structure.Alternate = GPIO_AF12_FMC; + + /* GPIOD configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_8 |\ + GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 |\ + GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOD, &gpio_init_structure); + + /* GPIOE configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_3| GPIO_PIN_4 | GPIO_PIN_7 |\ + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 |\ + GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOE, &gpio_init_structure); + + /* GPIOF configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; + HAL_GPIO_Init(GPIOF, &gpio_init_structure); + + /* GPIOG configuration */ + gpio_init_structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2| GPIO_PIN_3 | GPIO_PIN_4 |\ + GPIO_PIN_5 | GPIO_PIN_6; + HAL_GPIO_Init(GPIOG, &gpio_init_structure); + + /* Configure common DMA parameters */ + dma_handle.Init.Channel = SRAM_DMAx_CHANNEL; + dma_handle.Init.Direction = DMA_MEMORY_TO_MEMORY; + dma_handle.Init.PeriphInc = DMA_PINC_ENABLE; + dma_handle.Init.MemInc = DMA_MINC_ENABLE; + dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + dma_handle.Init.Mode = DMA_NORMAL; + dma_handle.Init.Priority = DMA_PRIORITY_HIGH; + dma_handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + dma_handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + dma_handle.Init.MemBurst = DMA_MBURST_SINGLE; + dma_handle.Init.PeriphBurst = DMA_PBURST_SINGLE; + + dma_handle.Instance = SRAM_DMAx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(hsram, hdma, dma_handle); + + /* Deinitialize the Stream for new transfer */ + HAL_DMA_DeInit(&dma_handle); + + /* Configure the DMA Stream */ + HAL_DMA_Init(&dma_handle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SRAM_DMAx_IRQn, 0x0F, 0); + HAL_NVIC_EnableIRQ(SRAM_DMAx_IRQn); +} + + +/** + * @brief DeInitializes SRAM MSP. + * @param hsram: SRAM handle + * @param Params + * @retval None + */ +__weak void BSP_SRAM_MspDeInit(SRAM_HandleTypeDef *hsram, void *Params) +{ + static DMA_HandleTypeDef dma_handle; + + /* Disable NVIC configuration for DMA interrupt */ + HAL_NVIC_DisableIRQ(SRAM_DMAx_IRQn); + + /* Deinitialize the stream for new transfer */ + dma_handle.Instance = SRAM_DMAx_STREAM; + HAL_DMA_DeInit(&dma_handle); + + /* GPIO pins clock, FMC clock and DMA clock can be shut down in the applications + by surcharging this __weak function */ +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sram.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sram.h new file mode 100644 index 00000000..1563a802 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_sram.h @@ -0,0 +1,148 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_sram.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_eval_sram.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_EVAL_SRAM_H +#define __STM32F769I_EVAL_SRAM_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @addtogroup STM32F769I_EVAL_SRAM + * @{ + */ + +/** @defgroup STM32F769I_EVAL_SRAM_Exported_Types SRAM Exported Types + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SRAM_Exported_Constants SRAM Exported Constants + * @{ + */ + +/** + * @brief SRAM status structure definition + */ +#define SRAM_OK ((uint8_t)0x00) +#define SRAM_ERROR ((uint8_t)0x01) + +#define SRAM_DEVICE_ADDR ((uint32_t)0x68000000) +#define SRAM_DEVICE_SIZE ((uint32_t)0x200000) /* SRAM device size in MBytes */ + +/* #define SRAM_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_8*/ +#define SRAM_MEMORY_WIDTH FMC_NORSRAM_MEM_BUS_WIDTH_16 + +#define SRAM_BURSTACCESS FMC_BURST_ACCESS_MODE_DISABLE +/* #define SRAM_BURSTACCESS FMC_BURST_ACCESS_MODE_ENABLE*/ + +#define SRAM_WRITEBURST FMC_WRITE_BURST_DISABLE +/* #define SRAM_WRITEBURST FMC_WRITE_BURST_ENABLE */ + +#define CONTINUOUSCLOCK_FEATURE FMC_CONTINUOUS_CLOCK_SYNC_ONLY +/* #define CONTINUOUSCLOCK_FEATURE FMC_CONTINUOUS_CLOCK_SYNC_ASYNC */ + +/* DMA definitions for SRAM DMA transfer */ +#define __SRAM_DMAx_CLK_ENABLE __HAL_RCC_DMA2_CLK_ENABLE +#define __SRAM_DMAx_CLK_DISABLE __HAL_RCC_DMA2_CLK_DISABLE +#define SRAM_DMAx_CHANNEL DMA_CHANNEL_0 +#define SRAM_DMAx_STREAM DMA2_Stream4 +#define SRAM_DMAx_IRQn DMA2_Stream4_IRQn +#define BSP_SRAM_DMA_IRQHandler DMA2_Stream4_IRQHandler +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SRAM_Exported_Macro SRAM Exported Macro + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_SRAM_Exported_Functions SRAM Exported Functions + * @{ + */ +uint8_t BSP_SRAM_Init(void); +uint8_t BSP_SRAM_DeInit(void); +uint8_t BSP_SRAM_ReadData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_SRAM_ReadData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_SRAM_WriteData(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); +uint8_t BSP_SRAM_WriteData_DMA(uint32_t uwStartAddress, uint16_t *pData, uint32_t uwDataSize); + +/* These functions can be modified in case the current settings (e.g. DMA stream) + need to be changed for specific application needs */ +void BSP_SRAM_MspInit(SRAM_HandleTypeDef *hsram, void *Params); +void BSP_SRAM_MspDeInit(SRAM_HandleTypeDef *hsram, void *Params); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_EVAL_SRAM_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_ts.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_ts.c new file mode 100644 index 00000000..0e819171 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_ts.c @@ -0,0 +1,499 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_ts.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the Touch + * Screen on STM32F769I-EVAL evaluation board. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* File Info : ----------------------------------------------------------------- + User NOTES +1. How To use this driver: +-------------------------- + - This driver is used to drive the touch screen module of the STM32F769I-EVAL + evaluation board on the K.O.D Optica Technology 480x800 TFT-LCD mounted on + MB1166 daughter board. The touch screen driver IC inside the K.O.D module KM-040TMP-02 + is a FT6206 by Focal Tech. + +2. Driver description: +--------------------- + + Initialization steps: + o Initialize the TS module using the BSP_TS_Init() function. This + function includes the MSP layer hardware resources initialization and the + communication layer configuration to start the TS use. The LCD size properties + (x and y) are passed as parameters. + o If TS interrupt mode is desired, you must configure the TS interrupt mode + by calling the function BSP_TS_ITConfig(). The TS interrupt mode is generated + as an external interrupt whenever a touch is detected. + The interrupt mode internally uses the IO functionalities driver driven by + the IO expander, to configure the IT line. + + + Touch screen use + o The touch screen state is captured whenever the function BSP_TS_GetState() is + used. This function returns information about the last LCD touch occurred + in the TS_StateTypeDef structure. + o If TS interrupt mode is used, the function BSP_TS_ITGetStatus() is needed to get + the interrupt status. To clear the IT pending bits, you should call the + function BSP_TS_ITClear(). + o The IT is handled using the corresponding external interrupt IRQ handler, + the user IT callback treatment is implemented on the same external interrupt + callback. + +------------------------------------------------------------------------------*/ +/* Dependencies +- stm32f769i_eval_lcd.c +- ft6x06.c +EndDependencies */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval.h" +#include "stm32f769i_eval_ts.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @defgroup STM32F769I_EVAL_TS STM32F769I_EVAL TS + * @{ + */ + +/** @defgroup STM32F769I_EVAL_TS_Private_Types_Definitions TS Private Types Definitions + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_TS_Private_Defines TS Private Types Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_TS_Private_Macros TS Private Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_TS_Imported_Variables TS Imported Variables + * @{ + */ + /** + * @} + */ + +/** @defgroup STM32F769I_EVAL_TS_Private_Variables TS Private Variables + * @{ + */ +static TS_DrvTypeDef *ts_driver; +static uint8_t ts_orientation; +uint8_t I2C_Address = 0; + +/* Table for touchscreen event information display on LCD : table indexed on enum @ref TS_TouchEventTypeDef information */ +char * ts_event_string_tab[TOUCH_EVENT_NB_MAX] = { "None", + "Press down", + "Lift up", + "Contact" + }; + +/* Table for touchscreen gesture Id information display on LCD : table indexed on enum @ref TS_GestureIdTypeDef information */ +char * ts_gesture_id_string_tab[GEST_ID_NB_MAX] = { "None", + "Move Up", + "Move Right", + "Move Down", + "Move Left", + "Zoom In", + "Zoom Out" + }; + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_TS_Private_Function_Prototypes TS Private Function Prototypes + * @{ + */ + +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_TS_Public_Functions TS Public Functions + * @{ + */ + +/** + * @brief Initializes and configures the touch screen functionalities and + * configures all necessary hardware resources (GPIOs, I2C, clocks..). + * @param ts_SizeX : Maximum X size of the TS area on LCD + * @param ts_SizeY : Maximum Y size of the TS area on LCD + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY) +{ + uint8_t ts_status = TS_OK; + uint8_t ts_id1, ts_id2 = 0; + /* Note : I2C_Address is un-initialized here, but is not used at all in init function */ + /* but the prototype of Init() is like that in template and should be respected */ + + /* Initialize the communication channel to sensor (I2C) if necessary */ + /* that is initialization is done only once after a power up */ + ft6x06_ts_drv.Init(I2C_Address); + + ts_id1 = ft6x06_ts_drv.ReadID(TS_I2C_ADDRESS); + if(ts_id1 != FT6206_ID_VALUE) + { + ts_id2 = ft6x06_ts_drv.ReadID(TS_I2C_ADDRESS_A02); + I2C_Address = TS_I2C_ADDRESS_A02; + } + else + { + I2C_Address = TS_I2C_ADDRESS; + } + + /* Scan FT6xx6 TouchScreen IC controller ID register by I2C Read */ + /* Verify this is a FT6206 or FT6336G, otherwise this is an error case */ + if((ts_id1 == FT6206_ID_VALUE) || (ts_id2 == FT6206_ID_VALUE)) + { + /* Found FT6206 : Initialize the TS driver structure */ + ts_driver = &ft6x06_ts_drv; + + /* Get LCD chosen orientation */ + if(ts_SizeX < ts_SizeY) + { + ts_orientation = TS_SWAP_NONE; + } + else + { + ts_orientation = TS_SWAP_XY | TS_SWAP_Y; + } + + if(ts_status == TS_OK) + { + /* Software reset the TouchScreen */ + ts_driver->Reset(I2C_Address); + + /* Calibrate, Configure and Start the TouchScreen driver */ + ts_driver->Start(I2C_Address); + + } /* of if(ts_status == TS_OK) */ + } + else + { + ts_status = TS_DEVICE_NOT_FOUND; + } + + return (ts_status); +} + +/** + * @brief Configures and enables the touch screen interrupts. + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_ITConfig(void) +{ + uint8_t ts_status = TS_ERROR; + uint8_t io_status = IO_ERROR; + + /* Initialize the IO */ + io_status = BSP_IO_Init(); + if(io_status != IO_OK) + { + return (ts_status); + } + + /* Configure TS IT line IO : is active low on FT6206 (see data sheet) */ + /* Configure TS_INT_PIN (MFX_IO_14) low level to generate MFX_IRQ_OUT in EXTI on MCU */ + io_status = BSP_IO_ConfigPin(TS_INT_PIN, IO_MODE_IT_LOW_LEVEL_PU); + if(io_status != IO_OK) + { + return (ts_status); + } + + /* Enable the TS in interrupt mode */ + /* In that case the INT output of FT6206 when new touch is available */ + /* is active low and directed on MFX IO14 */ + ts_driver->EnableIT(I2C_Address); + + /* If arrived here : set good status on exit */ + ts_status = TS_OK; + + return (ts_status); +} + +/** + * @brief Gets the touch screen interrupt status. + * @retval TS_IRQ_PENDING if touchscreen IRQ is pending, TS_NO_IRQ_PENDING when no IRQ TS is pending. + */ +uint8_t BSP_TS_ITGetStatus(void) +{ + uint8_t itStatus = TS_NO_IRQ_PENDING; /* By default no IRQ TS pending */ + uint32_t mfx_irq_status = 0; /* No MFX IRQ by default */ + + /* Check status of MFX_IO14 in particular which is the Touch Screen INT pin active low */ + mfx_irq_status = BSP_IO_ITGetStatus(TS_INT_PIN); + if(mfx_irq_status != 0) /* Note : returned mfx_irq_status = 0x4000 == (1<touchDetected = ts_driver->DetectTouch(I2C_Address); + if(TS_State->touchDetected) + { + for(index=0; index < TS_State->touchDetected; index++) + { + /* Get each touch coordinates */ + ts_driver->GetXY(I2C_Address, &(Raw_x[index]), &(Raw_y[index])); + + if(ts_orientation & TS_SWAP_XY) + { + tmp = Raw_x[index]; + Raw_x[index] = Raw_y[index]; + Raw_y[index] = tmp; + } + + if(ts_orientation & TS_SWAP_X) + { + Raw_x[index] = FT_6206_MAX_WIDTH - 1 - Raw_x[index]; + } + + if(ts_orientation & TS_SWAP_Y) + { + Raw_y[index] = FT_6206_MAX_HEIGHT - 1 - Raw_y[index]; + } + + xDiff = Raw_x[index] > _x[index]? (Raw_x[index] - _x[index]): (_x[index] - Raw_x[index]); + yDiff = Raw_y[index] > _y[index]? (Raw_y[index] - _y[index]): (_y[index] - Raw_y[index]); + + if ((xDiff + yDiff) > 5) + { + _x[index] = Raw_x[index]; + _y[index] = Raw_y[index]; + } + + + TS_State->touchX[index] = _x[index]; + TS_State->touchY[index] = _y[index]; + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + + /* Get touch info related to the current touch */ + ft6x06_TS_GetTouchInfo(I2C_Address, index, &weight, &area, &event); + + /* Update TS_State structure */ + TS_State->touchWeight[index] = weight; + TS_State->touchArea[index] = area; + + /* Remap touch event */ + switch(event) + { + case FT6206_TOUCH_EVT_FLAG_PRESS_DOWN : + TS_State->touchEventId[index] = TOUCH_EVENT_PRESS_DOWN; + break; + case FT6206_TOUCH_EVT_FLAG_LIFT_UP : + TS_State->touchEventId[index] = TOUCH_EVENT_LIFT_UP; + break; + case FT6206_TOUCH_EVT_FLAG_CONTACT : + TS_State->touchEventId[index] = TOUCH_EVENT_CONTACT; + break; + case FT6206_TOUCH_EVT_FLAG_NO_EVENT : + TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT; + break; + default : + ts_status = TS_ERROR; + break; + } /* of switch(event) */ + +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + } /* of for(index=0; index < TS_State->touchDetected; index++) */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + /* Get gesture Id */ + ts_status = BSP_TS_Get_GestureId(TS_State); +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + } /* end of if(TS_State->touchDetected != 0) */ + + return (ts_status); +} + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +/** + * @brief Update gesture Id following a touch detected. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if all initializations are OK. Other value if error. + */ +uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State) +{ + uint32_t gestureId = 0; + uint8_t ts_status = TS_OK; + + /* Get gesture Id */ + ft6x06_TS_GetGestureID(I2C_Address, &gestureId); + + /* Remap gesture Id to a TS_GestureIdTypeDef value */ + switch(gestureId) + { + case FT6206_GEST_ID_NO_GESTURE : + TS_State->gestureId = GEST_ID_NO_GESTURE; + break; + case FT6206_GEST_ID_MOVE_UP : + TS_State->gestureId = GEST_ID_MOVE_UP; + break; + case FT6206_GEST_ID_MOVE_RIGHT : + TS_State->gestureId = GEST_ID_MOVE_RIGHT; + break; + case FT6206_GEST_ID_MOVE_DOWN : + TS_State->gestureId = GEST_ID_MOVE_DOWN; + break; + case FT6206_GEST_ID_MOVE_LEFT : + TS_State->gestureId = GEST_ID_MOVE_LEFT; + break; + case FT6206_GEST_ID_ZOOM_IN : + TS_State->gestureId = GEST_ID_ZOOM_IN; + break; + case FT6206_GEST_ID_ZOOM_OUT : + TS_State->gestureId = GEST_ID_ZOOM_OUT; + break; + default : + ts_status = TS_ERROR; + break; + } /* of switch(gestureId) */ + + return(ts_status); +} +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + + +/** + * @brief Clears all touch screen interrupts. + */ +void BSP_TS_ITClear(void) +{ + /* Clear TS_INT_PIN IRQ in MFX */ + BSP_IO_ITClearPin(TS_INT_PIN); +} + + +/** @defgroup STM32F769I_EVAL_TS_Private_Functions TS Private Functions + * @{ + */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +/** + * @brief Function used to reset all touch data before a new acquisition + * of touch information. + * @param TS_State: Pointer to touch screen current state structure + * @retval TS_OK if OK, TE_ERROR if problem found. + */ +uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State) +{ + uint8_t ts_status = TS_ERROR; + uint32_t index; + + if (TS_State != (TS_StateTypeDef *)NULL) + { + TS_State->gestureId = GEST_ID_NO_GESTURE; + TS_State->touchDetected = 0; + + for(index = 0; index < TS_MAX_NB_TOUCH; index++) + { + TS_State->touchX[index] = 0; + TS_State->touchY[index] = 0; + TS_State->touchArea[index] = 0; + TS_State->touchEventId[index] = TOUCH_EVENT_NO_EVT; + TS_State->touchWeight[index] = 0; + } + + ts_status = TS_OK; + + } /* of if (TS_State != (TS_StateTypeDef *)NULL) */ + + return (ts_status); +} +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_ts.h b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_ts.h new file mode 100644 index 00000000..26541091 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I_EVAL/stm32f769i_eval_ts.h @@ -0,0 +1,210 @@ +/** + ****************************************************************************** + * @file stm32f769i_eval_ts.h + * @author MCD Application Team + * @brief This file contains the common defines and functions prototypes for + * the stm32f769i_eval_ts.c driver. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F769I_EVAL_TS_H +#define __STM32F769I_EVAL_TS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f769i_eval.h" +#include "stm32f769i_eval_lcd.h" +#include "stm32f769i_eval_io.h" + +/* Include TouchScreen component driver */ +#include "../Components/ft6x06/ft6x06.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F769I_EVAL + * @{ + */ + +/** @addtogroup STM32F769I_EVAL_TS STM32F769I_EVAL TS + * @{ + */ + + /** @defgroup STM32F769I_EVAL_TS_Exported_Constants TS Exported Constants + * @{ + */ +/** @brief With FT6206 : maximum 2 touches detected simultaneously + */ +#define TS_MAX_NB_TOUCH ((uint32_t) FT6206_MAX_DETECTABLE_TOUCH) + +#define TS_NO_IRQ_PENDING ((uint8_t) 0) +#define TS_IRQ_PENDING ((uint8_t) 1) + +#define TS_SWAP_NONE ((uint8_t) 0x01) +#define TS_SWAP_X ((uint8_t) 0x02) +#define TS_SWAP_Y ((uint8_t) 0x04) +#define TS_SWAP_XY ((uint8_t) 0x08) + + /** + * @} + */ + +/** @defgroup STM32F769I_EVAL_TS_Exported_Types TS Exported Types + * @{ + */ +/** +* @brief TS_StateTypeDef +* Define TS State structure +*/ +typedef struct +{ + uint8_t touchDetected; /*!< Total number of active touches detected at last scan */ + uint16_t touchX[TS_MAX_NB_TOUCH]; /*!< Touch X[0], X[1] coordinates on 12 bits */ + uint16_t touchY[TS_MAX_NB_TOUCH]; /*!< Touch Y[0], Y[1] coordinates on 12 bits */ + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) + uint8_t touchWeight[TS_MAX_NB_TOUCH]; /*!< Touch_Weight[0], Touch_Weight[1] : weight property of touches */ + uint8_t touchEventId[TS_MAX_NB_TOUCH]; /*!< Touch_EventId[0], Touch_EventId[1] : take value of type @ref TS_TouchEventTypeDef */ + uint8_t touchArea[TS_MAX_NB_TOUCH]; /*!< Touch_Area[0], Touch_Area[1] : touch area of each touch */ + uint32_t gestureId; /*!< type of gesture detected : take value of type @ref TS_GestureIdTypeDef */ +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +} TS_StateTypeDef; + +/** + * @brief TS_StatusTypeDef + * Define BSP_TS_xxx() functions possible return value, + * when status is returned by those functions. + */ +typedef enum +{ + TS_OK = 0x00, /*!< Touch Ok */ + TS_ERROR = 0x01, /*!< Touch Error */ + TS_TIMEOUT = 0x02, /*!< Touch Timeout */ + TS_DEVICE_NOT_FOUND = 0x03 /*!< Touchscreen device not found */ +} TS_StatusTypeDef; + +/** + * @brief TS_GestureIdTypeDef + * Define Possible managed gesture identification values returned by touch screen + * driver. + */ +typedef enum +{ + GEST_ID_NO_GESTURE = 0x00, /*!< Gesture not defined / recognized */ + GEST_ID_MOVE_UP = 0x01, /*!< Gesture Move Up */ + GEST_ID_MOVE_RIGHT = 0x02, /*!< Gesture Move Right */ + GEST_ID_MOVE_DOWN = 0x03, /*!< Gesture Move Down */ + GEST_ID_MOVE_LEFT = 0x04, /*!< Gesture Move Left */ + GEST_ID_ZOOM_IN = 0x05, /*!< Gesture Zoom In */ + GEST_ID_ZOOM_OUT = 0x06, /*!< Gesture Zoom Out */ + GEST_ID_NB_MAX = 0x07 /*!< max number of gesture id */ +} TS_GestureIdTypeDef; + +/** + * @brief TS_TouchEventTypeDef + * Define Possible touch events kind as returned values + * by touch screen IC Driver. + */ +typedef enum +{ + TOUCH_EVENT_NO_EVT = 0x00, /*!< Touch Event : undetermined */ + TOUCH_EVENT_PRESS_DOWN = 0x01, /*!< Touch Event Press Down */ + TOUCH_EVENT_LIFT_UP = 0x02, /*!< Touch Event Lift Up */ + TOUCH_EVENT_CONTACT = 0x03, /*!< Touch Event Contact */ + TOUCH_EVENT_NB_MAX = 0x04 /*!< max number of touch events kind */ +} TS_TouchEventTypeDef; + +/** + * @} + */ + +/** @addtogroup STM32F769I_EVAL_TS_Imported_Variables + * @{ + */ +/** + * @brief Table for touchscreen event information display on LCD : + * table indexed on enum @ref TS_TouchEventTypeDef information + */ +extern char * ts_event_string_tab[TOUCH_EVENT_NB_MAX]; + +/** + * @brief Table for touchscreen gesture Id information display on LCD : table indexed + * on enum @ref TS_GestureIdTypeDef information + */ +extern char * ts_gesture_id_string_tab[GEST_ID_NB_MAX]; +/** + * @} + */ + +/** @defgroup STM32F769I_EVAL_TS_Exported_Functions TS Exported Functions + * @{ + */ +uint8_t BSP_TS_Init(uint16_t ts_SizeX, uint16_t ts_SizeY); +uint8_t BSP_TS_GetState(TS_StateTypeDef *TS_State); + +#if (TS_MULTI_TOUCH_SUPPORTED == 1) +uint8_t BSP_TS_Get_GestureId(TS_StateTypeDef *TS_State); +uint8_t BSP_TS_ResetTouchData(TS_StateTypeDef *TS_State); +#endif /* TS_MULTI_TOUCH_SUPPORTED == 1 */ + +uint8_t BSP_TS_ITConfig(void); +uint8_t BSP_TS_ITGetStatus(void); +void BSP_TS_ITClear(void); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F769I_EVAL_TS_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7xx_Nucleo_144/Release_Notes.html b/src/port_stm32f7/common/bsp_drivers/STM32F7xx_Nucleo_144/Release_Notes.html new file mode 100644 index 00000000..aa791a56 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7xx_Nucleo_144/Release_Notes.html @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + Release Notes for STM32F7xx-Nucleo Board Drivers + + + + + + + + + + +
+


+

+
+ + + + + + +
+ + + + + + + + + +
+

Back to Release page

+
+

Release +Notes for STM32F7xx_Nucleo_144 Board Drivers

+

Copyright +2015 STMicroelectronics

+ +

+

+
+

 

+ + + + + + +

Update History

V1.0.0 / 18-November-2015

+ +

Main +Changes

+ +
  • First official release

License

+
+
+Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met:
+
+
  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions +in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of STMicroelectronics nor the names of its contributors may be used to endorse or promote products derived
    +
    +
+        from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ +
+
+ + +
+
+
For +complete documentation on STM32 Microcontrollers +visit www.st.com/STM32
+
+

+
+
+

 

+
+ + \ No newline at end of file diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7xx_Nucleo_144/stm32f7xx_nucleo_144.c b/src/port_stm32f7/common/bsp_drivers/STM32F7xx_Nucleo_144/stm32f7xx_nucleo_144.c new file mode 100644 index 00000000..405f83db --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7xx_Nucleo_144/stm32f7xx_nucleo_144.c @@ -0,0 +1,919 @@ +/** + ****************************************************************************** + * @file stm32f7xx_nucleo_144.c + * @author MCD Application Team + * @version V1.0.0 + * @date 18-November-2015 + * @brief This file provides set of firmware functions to manage: + * - LEDs and push-button available on STM32F7XX-Nucleo-144 Kit + * from STMicroelectronics + * - LCD, joystick and microSD available on Adafruit 1.8" TFT LCD + * shield (reference ID 802) + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_nucleo_144.h" + + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7XX_NUCLEO_144 + * @{ + */ + +/** @addtogroup STM32F7XX_NUCLEO_144_LOW_LEVEL + * @brief This file provides set of firmware functions to manage Leds and push-button + * available on STM32F7xx-Nucleo Kit from STMicroelectronics. + * @{ + */ + +/** @defgroup STM32F7XX_NUCLEO_144_LOW_LEVEL_Private_TypesDefinitions + * @{ + */ +/** + * @} + */ + + +/** @defgroup STM32F7XX_NUCLEO_144_LOW_LEVEL_Private_Defines + * @{ + */ + +/** + * @brief STM32F7xx NUCLEO BSP Driver version number V1.0.0 + */ +#define __STM32F7xx_NUCLEO_BSP_VERSION_MAIN (0x01) /*!< [31:24] main version */ +#define __STM32F7xx_NUCLEO_BSP_VERSION_SUB1 (0x00) /*!< [23:16] sub1 version */ +#define __STM32F7xx_NUCLEO_BSP_VERSION_SUB2 (0x00) /*!< [15:8] sub2 version */ +#define __STM32F7xx_NUCLEO_BSP_VERSION_RC (0x00) /*!< [7:0] release candidate */ +#define __STM32F7xx_NUCLEO_BSP_VERSION ((__STM32F7xx_NUCLEO_BSP_VERSION_MAIN << 24)\ + |(__STM32F7xx_NUCLEO_BSP_VERSION_SUB1 << 16)\ + |(__STM32F7xx_NUCLEO_BSP_VERSION_SUB2 << 8 )\ + |(__STM32F7xx_NUCLEO_BSP_VERSION_RC)) + +/** + * @brief LINK SD Card + */ +#define SD_DUMMY_BYTE 0xFF +#define SD_NO_RESPONSE_EXPECTED 0x80 + +/** + * @} + */ + +/** @defgroup STM32F7XX_NUCLEO_144_LOW_LEVEL_Private_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7XX_NUCLEO_144_LOW_LEVEL_Private_Variables + * @{ + */ +GPIO_TypeDef* GPIO_PORT[LEDn] = {LED1_GPIO_PORT, LED2_GPIO_PORT, LED3_GPIO_PORT}; + +const uint16_t GPIO_PIN[LEDn] = {LED1_PIN, LED2_PIN, LED3_PIN}; + +GPIO_TypeDef* BUTTON_PORT[BUTTONn] = {USER_BUTTON_GPIO_PORT}; +const uint16_t BUTTON_PIN[BUTTONn] = {USER_BUTTON_PIN}; +const uint8_t BUTTON_IRQn[BUTTONn] = {USER_BUTTON_EXTI_IRQn}; + +/** + * @brief BUS variables + */ + +#ifdef ADAFRUIT_TFT_JOY_SD_ID802 +#ifdef HAL_SPI_MODULE_ENABLED +uint32_t SpixTimeout = NUCLEO_SPIx_TIMEOUT_MAX; /*SR) & SPI_FLAG_TXE) != SPI_FLAG_TXE) + { + } + /* Need to invert bytes for LCD*/ + *((__IO uint8_t*)&hnucleo_Spi.Instance->DR) = *(pData+1); + + while(((hnucleo_Spi.Instance->SR) & SPI_FLAG_TXE) != SPI_FLAG_TXE) + { + } + *((__IO uint8_t*)&hnucleo_Spi.Instance->DR) = *pData; + counter--; + pData += 2; + } + + /* Wait until the bus is ready before releasing Chip select */ + while(((hnucleo_Spi.Instance->SR) & SPI_FLAG_BSY) != RESET) + { + } + } + + /* Empty the Rx fifo */ + data = *(&hnucleo_Spi.Instance->DR); + UNUSED(data); /* Remove GNU warning */ + + /* Deselect : Chip Select high */ + LCD_CS_HIGH(); +} + +/** + * @brief Wait for loop in ms. + * @param Delay in ms. + * @retval None + */ +void LCD_Delay(uint32_t Delay) +{ + HAL_Delay(Delay); +} +#endif /* HAL_SPI_MODULE_ENABLED */ + +/******************************* ADC driver ********************************/ +#ifdef HAL_ADC_MODULE_ENABLED + +/** + * @brief Initializes ADC MSP. + * @param None + * @retval None + */ +static void ADCx_MspInit(ADC_HandleTypeDef *hadc) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /*** Configure the GPIOs ***/ + /* Enable GPIO clock */ + NUCLEO_ADCx_GPIO_CLK_ENABLE(); + + /* Configure the selected ADC Channel as analog input */ + GPIO_InitStruct.Pin = NUCLEO_ADCx_GPIO_PIN ; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(NUCLEO_ADCx_GPIO_PORT, &GPIO_InitStruct); + + /*** Configure the ADC peripheral ***/ + /* Enable ADC clock */ + NUCLEO_ADCx_CLK_ENABLE(); +} + +/** + * @brief DeInitializes ADC MSP. + * @param None + * @note ADC DeInit does not disable the GPIO clock + * @retval None + */ +static void ADCx_MspDeInit(ADC_HandleTypeDef *hadc) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /*** DeInit the ADC peripheral ***/ + /* Disable ADC clock */ + NUCLEO_ADCx_CLK_DISABLE(); + + /* Configure the selected ADC Channel as analog input */ + GPIO_InitStruct.Pin = NUCLEO_ADCx_GPIO_PIN ; + HAL_GPIO_DeInit(NUCLEO_ADCx_GPIO_PORT, GPIO_InitStruct.Pin); + + /* Disable GPIO clock has to be done by the application*/ + /* NUCLEO_ADCx_GPIO_CLK_DISABLE(); */ +} + +/** + * @brief Initializes ADC HAL. + * @param None + * @retval None + */ +static void ADCx_Init(void) +{ + if(HAL_ADC_GetState(&hnucleo_Adc) == HAL_ADC_STATE_RESET) + { + /* ADC Config */ + hnucleo_Adc.Instance = NUCLEO_ADCx; + hnucleo_Adc.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4; /* (must not exceed 36MHz) */ + hnucleo_Adc.Init.Resolution = ADC_RESOLUTION12b; + hnucleo_Adc.Init.DataAlign = ADC_DATAALIGN_RIGHT; + hnucleo_Adc.Init.ContinuousConvMode = DISABLE; + hnucleo_Adc.Init.DiscontinuousConvMode = DISABLE; + hnucleo_Adc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + hnucleo_Adc.Init.EOCSelection = EOC_SINGLE_CONV; + hnucleo_Adc.Init.NbrOfConversion = 1; + hnucleo_Adc.Init.DMAContinuousRequests = DISABLE; + + ADCx_MspInit(&hnucleo_Adc); + HAL_ADC_Init(&hnucleo_Adc); + } +} + +/** + * @brief Initializes ADC HAL. + * @param None + * @retval None + */ +static void ADCx_DeInit(void) +{ + hnucleo_Adc.Instance = NUCLEO_ADCx; + + HAL_ADC_DeInit(&hnucleo_Adc); + ADCx_MspDeInit(&hnucleo_Adc); +} + +/******************************* LINK JOYSTICK ********************************/ + +/** + * @brief Configures joystick available on adafruit 1.8" TFT shield + * managed through ADC to detect motion. + * @param None + * @retval Joystickstatus (0=> success, 1=> fail) + */ +uint8_t BSP_JOY_Init(void) +{ + uint8_t status = HAL_ERROR; + + ADCx_Init(); + + /* Select the ADC Channel to be converted */ + sConfig.Channel = NUCLEO_ADCx_CHANNEL; + sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; + sConfig.Rank = 1; + status = HAL_ADC_ConfigChannel(&hnucleo_Adc, &sConfig); + + /* Return Joystick initialization status */ + return status; +} + +/** + * @brief DeInit joystick GPIOs. + * @note JOY DeInit does not disable the Mfx, just set the Mfx pins in Off mode + * @retval None. + */ +void BSP_JOY_DeInit(void) +{ + ADCx_DeInit(); +} + +/** + * @brief Returns the Joystick key pressed. + * @note To know which Joystick key is pressed we need to detect the voltage + * level on each key output + * - None : 3.3 V / 4095 + * - SEL : 1.055 V / 1308 + * - DOWN : 0.71 V / 88 + * - LEFT : 3.0 V / 3720 + * - RIGHT : 0.595 V / 737 + * - UP : 1.65 V / 2046 + * @retval JOYState_TypeDef: Code of the Joystick key pressed. + */ +JOYState_TypeDef BSP_JOY_GetState(void) +{ + JOYState_TypeDef state; + uint16_t keyconvertedvalue = 0; + + /* Start the conversion process */ + HAL_ADC_Start(&hnucleo_Adc); + + /* Wait for the end of conversion */ + HAL_ADC_PollForConversion(&hnucleo_Adc, 10); + + /* Check if the continuous conversion of regular channel is finished */ + if((HAL_ADC_GetState(&hnucleo_Adc) & HAL_ADC_STATE_EOC_REG) == HAL_ADC_STATE_EOC_REG) + + { + /* Get the converted value of regular channel */ + keyconvertedvalue = HAL_ADC_GetValue(&hnucleo_Adc); + } + + if((keyconvertedvalue > 2010) && (keyconvertedvalue < 2090)) + { + state = JOY_UP; + } + else if((keyconvertedvalue > 680) && (keyconvertedvalue < 780)) + { + state = JOY_RIGHT; + } + else if((keyconvertedvalue > 1270) && (keyconvertedvalue < 1350)) + { + state = JOY_SEL; + } + else if((keyconvertedvalue > 50) && (keyconvertedvalue < 130)) + { + state = JOY_DOWN; + } + else if((keyconvertedvalue > 3680) && (keyconvertedvalue < 3760)) + { + state = JOY_LEFT; + } + else + { + state = JOY_NONE; + } + + /* Loop while a key is pressed */ + if(state != JOY_NONE) + { + keyconvertedvalue = HAL_ADC_GetValue(&hnucleo_Adc); + } + /* Return the code of the Joystick key pressed */ + return state; +} +#endif /* HAL_ADC_MODULE_ENABLED */ + +#endif /* ADAFRUIT_TFT_JOY_SD_ID802 */ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F7xx_Nucleo_144/stm32f7xx_nucleo_144.h b/src/port_stm32f7/common/bsp_drivers/STM32F7xx_Nucleo_144/stm32f7xx_nucleo_144.h new file mode 100644 index 00000000..c1b02264 --- /dev/null +++ b/src/port_stm32f7/common/bsp_drivers/STM32F7xx_Nucleo_144/stm32f7xx_nucleo_144.h @@ -0,0 +1,347 @@ +/** + ****************************************************************************** + * @file stm32f7xx_nucleo_144.h + * @author MCD Application Team + * @version V1.0.0 + * @date 18-November-2015 + * @brief This file contains definitions for: + * - LEDs and push-button available on STM32F7XX-Nucleo-144 Kit + * from STMicroelectronics + * - LCD, joystick and microSD available on Adafruit 1.8" TFT LCD + * shield (reference ID 802) + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7XX_NUCLEO_144_H +#define __STM32F7XX_NUCLEO_144_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/* To be defined only if the board is provided with the related shield */ +/* https://www.adafruit.com/products/802 */ +#ifndef ADAFRUIT_TFT_JOY_SD_ID802 +#define ADAFRUIT_TFT_JOY_SD_ID802 +#endif + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32F7XX_NUCLEO_144 + * @{ + */ + +/** @addtogroup STM32F7XX_NUCLEO_144_LOW_LEVEL + * @{ + */ + +/** @defgroup STM32F7XX_NUCLEO_144_LOW_LEVEL_Exported_Types + * @{ + */ +typedef enum +{ + LED1 = 0, + LED_GREEN = LED1, + LED2 = 1, + LED_BLUE = LED2, + LED3 = 2, + LED_RED = LED3 +}Led_TypeDef; + +typedef enum +{ + BUTTON_USER = 0, + /* Alias */ + BUTTON_KEY = BUTTON_USER +}Button_TypeDef; + +typedef enum +{ + BUTTON_MODE_GPIO = 0, + BUTTON_MODE_EXTI = 1 +}ButtonMode_TypeDef; + +typedef enum +{ + JOY_NONE = 0, + JOY_SEL = 1, + JOY_DOWN = 2, + JOY_LEFT = 3, + JOY_RIGHT = 4, + JOY_UP = 5 +}JOYState_TypeDef; + +/** + * @} + */ + +/** @defgroup STM32F7XX_NUCLEO_144_LOW_LEVEL_Exported_Constants + * @{ + */ + +/** + * @brief Define for STM32F7XX_NUCLEO_144 board + */ +#if !defined (USE_STM32F7XX_NUCLEO_144) + #define USE_STM32F7XX_NUCLEO_144 +#endif + +/** @addtogroup STM32F7XX_NUCLEO_144_LOW_LEVEL_LED + * @{ + */ +#define LEDn 3 + +#define LED1_PIN GPIO_PIN_0 +#define LED1_GPIO_PORT GPIOB +#define LED1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define LED1_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE() + +#define LED2_PIN GPIO_PIN_7 +#define LED2_GPIO_PORT GPIOB +#define LED2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define LED2_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE() + +#define LED3_PIN GPIO_PIN_14 +#define LED3_GPIO_PORT GPIOB +#define LED3_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() +#define LED3_GPIO_CLK_DISABLE() __HAL_RCC_GPIOB_CLK_DISABLE() + +#define LEDx_GPIO_CLK_ENABLE(__INDEX__) do { if((__INDEX__) == 0) {__HAL_RCC_GPIOB_CLK_ENABLE();} else\ + {__HAL_RCC_GPIOB_CLK_ENABLE(); }} while(0) +#define LEDx_GPIO_CLK_DISABLE(__INDEX__) do { if((__INDEX__) == 0) {__HAL_RCC_GPIOB_CLK_DISABLE();} else\ + {__HAL_RCC_GPIOB_CLK_DISABLE(); }} while(0) +/** + * @} + */ + +/** @addtogroup STM32F7XX_NUCLEO_144_LOW_LEVEL_BUTTON + * @{ + */ +#define BUTTONn 1 + +/** + * @brief Key push-button + */ +#define USER_BUTTON_PIN GPIO_PIN_13 +#define USER_BUTTON_GPIO_PORT GPIOC +#define USER_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define USER_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE() +#define USER_BUTTON_EXTI_LINE GPIO_PIN_13 +#define USER_BUTTON_EXTI_IRQn EXTI15_10_IRQn + +#define BUTTONx_GPIO_CLK_ENABLE(__INDEX__) USER_BUTTON_GPIO_CLK_ENABLE() +#define BUTTONx_GPIO_CLK_DISABLE(__INDEX__) USER_BUTTON_GPIO_CLK_DISABLE() + +/* Aliases */ +#define KEY_BUTTON_PIN USER_BUTTON_PIN +#define KEY_BUTTON_GPIO_PORT USER_BUTTON_GPIO_PORT +#define KEY_BUTTON_GPIO_CLK_ENABLE() USER_BUTTON_GPIO_CLK_ENABLE() +#define KEY_BUTTON_GPIO_CLK_DISABLE() USER_BUTTON_GPIO_CLK_DISABLE() +#define KEY_BUTTON_EXTI_LINE USER_BUTTON_EXTI_LINE +#define KEY_BUTTON_EXTI_IRQn USER_BUTTON_EXTI_IRQn + + +/** + * @brief USB Pins definition + */ + + +#define OTG_FS1_OVER_CURRENT_PIN GPIO_PIN_7 +#define OTG_FS1_OVER_CURRENT_PORT GPIOG +#define OTG_FS1_OVER_CURRENT_PORT_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE() + +#define OTG_FS1_POWER_SWITCH_PIN GPIO_PIN_6 +#define OTG_FS1_POWER_SWITCH_PORT GPIOG +#define OTG_FS1_POWER_SWITCH_PORT_CLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE() + +/** + * @} + */ + +/** @addtogroup STM32F7XX_NUCLEO_144_LOW_LEVEL_BUS + * @{ + */ +/*############################### SPI_A #######################################*/ +#ifdef HAL_SPI_MODULE_ENABLED + +#define NUCLEO_SPIx SPI1 +#define NUCLEO_SPIx_CLK_ENABLE() __HAL_RCC_SPI1_CLK_ENABLE() + +#define NUCLEO_SPIx_SCK_AF GPIO_AF5_SPI1 +#define NUCLEO_SPIx_SCK_GPIO_PORT GPIOA +#define NUCLEO_SPIx_SCK_PIN GPIO_PIN_5 +#define NUCLEO_SPIx_SCK_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define NUCLEO_SPIx_SCK_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() + +#define NUCLEO_SPIx_MISO_MOSI_AF GPIO_AF5_SPI1 +#define NUCLEO_SPIx_MISO_MOSI_GPIO_PORT GPIOA +#define NUCLEO_SPIx_MISO_MOSI_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() +#define NUCLEO_SPIx_MISO_MOSI_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE() +#define NUCLEO_SPIx_MISO_PIN GPIO_PIN_6 +#define NUCLEO_SPIx_MOSI_PIN GPIO_PIN_7 +/* Maximum Timeout values for flags waiting loops. These timeouts are not based + on accurate values, they just guarantee that the application will not remain + stuck if the SPI communication is corrupted. + You may modify these timeout values depending on CPU frequency and application + conditions (interrupts routines ...). */ +#define NUCLEO_SPIx_TIMEOUT_MAX 1000 + +#define NUCLEO_SPIx_CS_GPIO_PORT GPIOD +#define NUCLEO_SPIx_CS_PIN GPIO_PIN_14 +#define NUCLEO_SPIx_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() +#define NUCLEO_SPIx_CS_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE() + +#define SPIx__CS_LOW() HAL_GPIO_WritePin(NUCLEO_SPIx_CS_GPIO_PORT, NUCLEO_SPIx_CS_PIN, GPIO_PIN_RESET) +#define SPIx__CS_HIGH() HAL_GPIO_WritePin(NUCLEO_SPIx_CS_GPIO_PORT, NUCLEO_SPIx_CS_PIN, GPIO_PIN_SET) + +/** + * @brief SD Control Lines management + */ +#define SD_CS_LOW() HAL_GPIO_WritePin(SD_CS_GPIO_PORT, SD_CS_PIN, GPIO_PIN_RESET) +#define SD_CS_HIGH() HAL_GPIO_WritePin(SD_CS_GPIO_PORT, SD_CS_PIN, GPIO_PIN_SET) + +/** + * @brief LCD Control Lines management + */ +#define LCD_CS_LOW() HAL_GPIO_WritePin(LCD_CS_GPIO_PORT, LCD_CS_PIN, GPIO_PIN_RESET) +#define LCD_CS_HIGH() HAL_GPIO_WritePin(LCD_CS_GPIO_PORT, LCD_CS_PIN, GPIO_PIN_SET) +#define LCD_DC_LOW() HAL_GPIO_WritePin(LCD_DC_GPIO_PORT, LCD_DC_PIN, GPIO_PIN_RESET) +#define LCD_DC_HIGH() HAL_GPIO_WritePin(LCD_DC_GPIO_PORT, LCD_DC_PIN, GPIO_PIN_SET) + +/** + * @brief SD Control Interface pins (shield D4) + */ +#define SD_CS_PIN GPIO_PIN_14 +#define SD_CS_GPIO_PORT GPIOF +#define SD_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() +#define SD_CS_GPIO_CLK_DISABLE() __HAL_RCC_GPIOF_CLK_DISABLE() + +/** + * @brief LCD Control Interface pins (shield D10) + */ +#define LCD_CS_PIN GPIO_PIN_14 +#define LCD_CS_GPIO_PORT GPIOD +#define LCD_CS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() +#define LCD_CS_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE() + +/** + * @brief LCD Data/Command Interface pins (shield D8) + */ +#define LCD_DC_PIN GPIO_PIN_12 +#define LCD_DC_GPIO_PORT GPIOF +#define LCD_DC_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() +#define LCD_DC_GPIO_CLK_DISABLE() __HAL_RCC_GPIOF_CLK_DISABLE() + +#endif /* HAL_SPI_MODULE_ENABLED */ + +/*################################ ADC3 ######################################*/ +/** + * @brief ADC Interface pins + * used to detect motion of Joystick available on Adafruit 1.8" TFT shield + */ + +#ifdef HAL_ADC_MODULE_ENABLED + +#define NUCLEO_ADCx ADC3 +#define NUCLEO_ADCx_CLK_ENABLE() __HAL_RCC_ADC3_CLK_ENABLE() +#define NUCLEO_ADCx_CLK_DISABLE() __HAL_RCC_ADC3_CLK_DISABLE() + +#define NUCLEO_ADCx_CHANNEL ADC_CHANNEL_9 + +#define NUCLEO_ADCx_GPIO_PORT GPIOF +#define NUCLEO_ADCx_GPIO_PIN GPIO_PIN_3 +#define NUCLEO_ADCx_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() +#define NUCLEO_ADCx_GPIO_CLK_DISABLE() __HAL_RCC_GPIOF_CLK_DISABLE() + +#endif /* HAL_ADC_MODULE_ENABLED */ + +/** + * @} + */ + +/** + * @} + */ + +/** @defgroup STM32F7XX_NUCLEO_144_LOW_LEVEL_Exported_Macros + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32F7XX_NUCLEO_144_LOW_LEVEL_Exported_Functions + * @{ + */ +uint32_t BSP_GetVersion(void); +void BSP_LED_Init(Led_TypeDef Led); +void BSP_LED_DeInit(Led_TypeDef Led); +void BSP_LED_On(Led_TypeDef Led); +void BSP_LED_Off(Led_TypeDef Led); +void BSP_LED_Toggle(Led_TypeDef Led); +void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef ButtonMode); +void BSP_PB_DeInit(Button_TypeDef Button); +uint32_t BSP_PB_GetState(Button_TypeDef Button); +#ifdef HAL_ADC_MODULE_ENABLED +uint8_t BSP_JOY_Init(void); +JOYState_TypeDef BSP_JOY_GetState(void); +void BSP_JOY_DeInit(void); +#endif /* HAL_ADC_MODULE_ENABLED */ + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7XX_NUCLEO_144_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/fatfs/00history.txt b/src/port_stm32f7/common/fatfs/00history.txt new file mode 100644 index 00000000..2d71a3d9 --- /dev/null +++ b/src/port_stm32f7/common/fatfs/00history.txt @@ -0,0 +1,288 @@ +---------------------------------------------------------------------------- + Revision history of FatFs module +---------------------------------------------------------------------------- + +R0.00 (February 26, 2006) + + Prototype. + + + +R0.01 (April 29, 2006) + + The first release. + + + +R0.02 (June 01, 2006) + + Added FAT12 support. + Removed unbuffered mode. + Fixed a problem on small (<32M) partition. + + + +R0.02a (June 10, 2006) + + Added a configuration option (_FS_MINIMUM). + + + +R0.03 (September 22, 2006) + + Added f_rename(). + Changed option _FS_MINIMUM to _FS_MINIMIZE. + + + +R0.03a (December 11, 2006) + + Improved cluster scan algorithm to write files fast. + Fixed f_mkdir() creates incorrect directory on FAT32. + + + +R0.04 (February 04, 2007) + + Added f_mkfs(). + Supported multiple drive system. + Changed some interfaces for multiple drive system. + Changed f_mountdrv() to f_mount(). + + + +R0.04a (April 01, 2007) + + Supported multiple partitions on a physical drive. + Added a capability of extending file size to f_lseek(). + Added minimization level 3. + Fixed an endian sensitive code in f_mkfs(). + + + +R0.04b (May 05, 2007) + + Added a configuration option _USE_NTFLAG. + Added FSINFO support. + Fixed DBCS name can result FR_INVALID_NAME. + Fixed short seek (<= csize) collapses the file object. + + + +R0.05 (August 25, 2007) + + Changed arguments of f_read(), f_write() and f_mkfs(). + Fixed f_mkfs() on FAT32 creates incorrect FSINFO. + Fixed f_mkdir() on FAT32 creates incorrect directory. + + + +R0.05a (February 03, 2008) + + Added f_truncate() and f_utime(). + Fixed off by one error at FAT sub-type determination. + Fixed btr in f_read() can be mistruncated. + Fixed cached sector is not flushed when create and close without write. + + + +R0.06 (April 01, 2008) + + Added fputc(), fputs(), fprintf() and fgets(). + Improved performance of f_lseek() on moving to the same or following cluster. + + + +R0.07 (April 01, 2009) + + Merged Tiny-FatFs as a configuration option. (_FS_TINY) + Added long file name feature. (_USE_LFN) + Added multiple code page feature. (_CODE_PAGE) + Added re-entrancy for multitask operation. (_FS_REENTRANT) + Added auto cluster size selection to f_mkfs(). + Added rewind option to f_readdir(). + Changed result code of critical errors. + Renamed string functions to avoid name collision. + + + +R0.07a (April 14, 2009) + + Septemberarated out OS dependent code on reentrant cfg. + Added multiple sector size feature. + + + +R0.07c (June 21, 2009) + + Fixed f_unlink() can return FR_OK on error. + Fixed wrong cache control in f_lseek(). + Added relative path feature. + Added f_chdir() and f_chdrive(). + Added proper case conversion to extended character. + + + +R0.07e (November 03, 2009) + + Septemberarated out configuration options from ff.h to ffconf.h. + Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH. + Fixed name matching error on the 13 character boundary. + Added a configuration option, _LFN_UNICODE. + Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. + + + +R0.08 (May 15, 2010) + + Added a memory configuration option. (_USE_LFN = 3) + Added file lock feature. (_FS_SHARE) + Added fast seek feature. (_USE_FASTSEEK) + Changed some types on the API, XCHAR->TCHAR. + Changed .fname in the FILINFO structure on Unicode cfg. + String functions support UTF-8 encoding files on Unicode cfg. + + + +R0.08a (August 16, 2010) + + Added f_getcwd(). (_FS_RPATH = 2) + Added sector erase feature. (_USE_ERASE) + Moved file lock semaphore table from fs object to the bss. + Fixed f_mkfs() creates wrong FAT32 volume. + + + +R0.08b (January 15, 2011) + + Fast seek feature is also applied to f_read() and f_write(). + f_lseek() reports required table size on creating CLMP. + Extended format syntax of f_printf(). + Ignores duplicated directory separators in given path name. + + + +R0.09 (September 06, 2011) + + f_mkfs() supports multiple partition to complete the multiple partition feature. + Added f_fdisk(). + + + +R0.09a (August 27, 2012) + + Changed f_open() and f_opendir() reject null object pointer to avoid crash. + Changed option name _FS_SHARE to _FS_LOCK. + Fixed assertion failure due to OS/2 EA on FAT12/16 volume. + + + +R0.09b (January 24, 2013) + + Added f_setlabel() and f_getlabel(). + + + +R0.10 (October 02, 2013) + + Added selection of character encoding on the file. (_STRF_ENCODE) + Added f_closedir(). + Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO) + Added forced mount feature with changes of f_mount(). + Improved behavior of volume auto detection. + Improved write throughput of f_puts() and f_printf(). + Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write(). + Fixed f_write() can be truncated when the file size is close to 4GB. + Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error. + + + +R0.10a (January 15, 2014) + + Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID) + Added a configuration option of minimum sector size. (_MIN_SS) + 2nd argument of f_rename() can have a drive number and it will be ignored. + Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10) + Fixed f_close() invalidates the file object without volume lock. + Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10) + Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07) + + + +R0.10b (May 19, 2014) + + Fixed a hard error in the disk I/O layer can collapse the directory entry. + Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07) + + + +R0.10c (November 09, 2014) + + Added a configuration option for the platforms without RTC. (_FS_NORTC) + Changed option name _USE_ERASE to _USE_TRIM. + Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b) + Fixed a potential problem of FAT access that can appear on disk error. + Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08) + + + +R0.11 (February 09, 2015) + + Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND) + Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c) + Fixed _FS_NORTC option does not work properly. (appeared at R0.10c) + + + +R0.11a (September 05, 2015) + + Fixed wrong media change can lead a deadlock at thread-safe configuration. + Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE) + Removed some code pages actually not exist on the standard systems. (_CODE_PAGE) + Fixed errors in the case conversion teble of code page 437 and 850 (ff.c). + Fixed errors in the case conversion teble of Unicode (cc*.c). + + + +R0.12 (April 12, 2016) + + Added support for exFAT file system. (_FS_EXFAT) + Added f_expand(). (_USE_EXPAND) + Changed some members in FINFO structure and behavior of f_readdir(). + Added an option _USE_CHMOD. + Removed an option _WORD_ACCESS. + Fixed errors in the case conversion table of Unicode (cc*.c). + + + +R0.12a (July 10, 2016) + + Added support for creating exFAT volume with some changes of f_mkfs(). + Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed. + f_forward() is available regardless of _FS_TINY. + Fixed f_mkfs() creates wrong volume. (appeared at R0.12) + Fixed wrong memory read in create_name(). (appeared at R0.12) + Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD. + + + +R0.12b (September 04, 2016) + + Made f_rename() be able to rename objects with the same name but case. + Fixed an error in the case conversion teble of code page 866. (ff.c) + Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12) + Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12) + Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12) + Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12) + Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12) + Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12) + + + +R0.12c (March 04, 2017) + + Improved write throughput at the fragmented file on the exFAT volume. + Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN. + Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12) + Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c) + diff --git a/src/port_stm32f7/common/fatfs/00readme.txt b/src/port_stm32f7/common/fatfs/00readme.txt new file mode 100644 index 00000000..dfa51ed0 --- /dev/null +++ b/src/port_stm32f7/common/fatfs/00readme.txt @@ -0,0 +1,21 @@ +FatFs Module Source Files R0.12c + + +FILES + + 00readme.txt This file. + 00history.txt Revision history. + ff.c FatFs module. + ffconf.h Configuration file of FatFs module. + ff.h Common include file for FatFs and application module. + diskio.h Common include file for FatFs and disk I/O module. + diskio.c An example of glue function to attach existing disk I/O module to FatFs. + integer.h Integer type definitions for FatFs. + option Optional external modules. + + + Low level disk I/O module is not included in this archive because the FatFs + module is only a generic file system layer and it does not depend on any specific + storage device. You have to provide a low level disk I/O module written to + control the storage device that attached to the target system. + diff --git a/src/port_stm32f7/common/fatfs/diskio.c b/src/port_stm32f7/common/fatfs/diskio.c new file mode 100644 index 00000000..5cf8edf4 --- /dev/null +++ b/src/port_stm32f7/common/fatfs/diskio.c @@ -0,0 +1,141 @@ +/*-----------------------------------------------------------------------*/ +/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2017 */ +/* */ +/* Portions COPYRIGHT 2017 STMicroelectronics */ +/* Portions Copyright (C) 2017, ChaN, all right reserved */ +/*-----------------------------------------------------------------------*/ +/* If a working storage control module is available, it should be */ +/* attached to the FatFs via a glue function rather than modifying it. */ +/* This is an example of glue functions to attach various existing */ +/* storage control modules to the FatFs module with a defined API. */ +/*-----------------------------------------------------------------------*/ + +/* Includes ------------------------------------------------------------------*/ +#include "diskio.h" +#include "ff_gen_drv.h" + +#if defined ( __GNUC__ ) +#ifndef __weak +#define __weak __attribute__((weak)) +#endif +#endif + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +extern Disk_drvTypeDef disk; + +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** + * @brief Gets Disk Status + * @param pdrv: Physical drive number (0..) + * @retval DSTATUS: Operation status + */ +DSTATUS disk_status ( + BYTE pdrv /* Physical drive number to identify the drive */ +) +{ + DSTATUS stat; + + stat = disk.drv[pdrv]->disk_status(disk.lun[pdrv]); + return stat; +} + +/** + * @brief Initializes a Drive + * @param pdrv: Physical drive number (0..) + * @retval DSTATUS: Operation status + */ +DSTATUS disk_initialize ( + BYTE pdrv /* Physical drive nmuber to identify the drive */ +) +{ + DSTATUS stat = RES_OK; + + if(disk.is_initialized[pdrv] == 0) + { + disk.is_initialized[pdrv] = 1; + stat = disk.drv[pdrv]->disk_initialize(disk.lun[pdrv]); + } + return stat; +} + +/** + * @brief Reads Sector(s) + * @param pdrv: Physical drive number (0..) + * @param *buff: Data buffer to store read data + * @param sector: Sector address (LBA) + * @param count: Number of sectors to read (1..128) + * @retval DRESULT: Operation result + */ +DRESULT disk_read ( + BYTE pdrv, /* Physical drive nmuber to identify the drive */ + BYTE *buff, /* Data buffer to store read data */ + DWORD sector, /* Sector address in LBA */ + UINT count /* Number of sectors to read */ +) +{ + DRESULT res; + + res = disk.drv[pdrv]->disk_read(disk.lun[pdrv], buff, sector, count); + return res; +} + +/** + * @brief Writes Sector(s) + * @param pdrv: Physical drive number (0..) + * @param *buff: Data to be written + * @param sector: Sector address (LBA) + * @param count: Number of sectors to write (1..128) + * @retval DRESULT: Operation result + */ +#if _USE_WRITE == 1 +DRESULT disk_write ( + BYTE pdrv, /* Physical drive nmuber to identify the drive */ + const BYTE *buff, /* Data to be written */ + DWORD sector, /* Sector address in LBA */ + UINT count /* Number of sectors to write */ +) +{ + DRESULT res; + + res = disk.drv[pdrv]->disk_write(disk.lun[pdrv], buff, sector, count); + return res; +} +#endif /* _USE_WRITE == 1 */ + +/** + * @brief I/O control operation + * @param pdrv: Physical drive number (0..) + * @param cmd: Control code + * @param *buff: Buffer to send/receive control data + * @retval DRESULT: Operation result + */ +#if _USE_IOCTL == 1 +DRESULT disk_ioctl ( + BYTE pdrv, /* Physical drive nmuber (0..) */ + BYTE cmd, /* Control code */ + void *buff /* Buffer to send/receive control data */ +) +{ + DRESULT res; + + res = disk.drv[pdrv]->disk_ioctl(disk.lun[pdrv], cmd, buff); + return res; +} +#endif /* _USE_IOCTL == 1 */ + +/** + * @brief Gets Time from RTC + * @param None + * @retval Time in DWORD + */ +__weak DWORD get_fattime (void) +{ + return 0; +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/port_stm32f7/common/fatfs/diskio.h b/src/port_stm32f7/common/fatfs/diskio.h new file mode 100644 index 00000000..5b61e570 --- /dev/null +++ b/src/port_stm32f7/common/fatfs/diskio.h @@ -0,0 +1,80 @@ +/*-----------------------------------------------------------------------/ +/ Low level disk interface modlue include file (C)ChaN, 2014 / +/-----------------------------------------------------------------------*/ + +#ifndef _DISKIO_DEFINED +#define _DISKIO_DEFINED + +#ifdef __cplusplus +extern "C" { +#endif + +#define _USE_WRITE 1 /* 1: Enable disk_write function */ +#define _USE_IOCTL 1 /* 1: Enable disk_ioctl function */ + +#include "integer.h" + + +/* Status of Disk Functions */ +typedef BYTE DSTATUS; + +/* Results of Disk Functions */ +typedef enum { + RES_OK = 0, /* 0: Successful */ + RES_ERROR, /* 1: R/W Error */ + RES_WRPRT, /* 2: Write Protected */ + RES_NOTRDY, /* 3: Not Ready */ + RES_PARERR /* 4: Invalid Parameter */ +} DRESULT; + + +/*---------------------------------------*/ +/* Prototypes for disk control functions */ + + +DSTATUS disk_initialize (BYTE pdrv); +DSTATUS disk_status (BYTE pdrv); +DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); +DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); +DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); +DWORD get_fattime (void); + +/* Disk Status Bits (DSTATUS) */ + +#define STA_NOINIT 0x01 /* Drive not initialized */ +#define STA_NODISK 0x02 /* No medium in the drive */ +#define STA_PROTECT 0x04 /* Write protected */ + + +/* Command code for disk_ioctrl fucntion */ + +/* Generic command (Used by FatFs) */ +#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ +#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ +#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ + +/* Generic command (Not used by FatFs) */ +#define CTRL_POWER 5 /* Get/Set power status */ +#define CTRL_LOCK 6 /* Lock/Unlock media removal */ +#define CTRL_EJECT 7 /* Eject media */ +#define CTRL_FORMAT 8 /* Create physical format on the media */ + +/* MMC/SDC specific ioctl command */ +#define MMC_GET_TYPE 10 /* Get card type */ +#define MMC_GET_CSD 11 /* Get CSD */ +#define MMC_GET_CID 12 /* Get CID */ +#define MMC_GET_OCR 13 /* Get OCR */ +#define MMC_GET_SDSTAT 14 /* Get SD status */ + +/* ATA/CF specific ioctl command */ +#define ATA_GET_REV 20 /* Get F/W revision */ +#define ATA_GET_MODEL 21 /* Get model name */ +#define ATA_GET_SN 22 /* Get serial number */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/port_stm32f7/common/fatfs/drivers/sd_diskio.c b/src/port_stm32f7/common/fatfs/drivers/sd_diskio.c new file mode 100644 index 00000000..0f2c25e6 --- /dev/null +++ b/src/port_stm32f7/common/fatfs/drivers/sd_diskio.c @@ -0,0 +1,226 @@ +/** + ****************************************************************************** + * @file sd_diskio_template_bspv1.c + * @author MCD Application Team + * @brief SD Disk I/O template driver based on BSP v1 api. This file needs + * to be renamed and copied into the application project alongside + * the respective header file + ****************************************************************************** + * @attention + * + * Copyright (c) 2017-2019 STMicroelectronics. All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** +**/ +/* Includes ------------------------------------------------------------------*/ +#include "ff_gen_drv.h" +#include "sd_diskio.h" + + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* use the default SD timout as defined in the platform BSP driver*/ +#if defined(SDMMC_DATATIMEOUT) +#define SD_TIMEOUT SDMMC_DATATIMEOUT +#elif defined(SD_DATATIMEOUT) +#define SD_TIMEOUT SD_DATATIMEOUT +#else +#define SD_TIMEOUT 30 * 1000 +#endif + +#define SD_DEFAULT_BLOCK_SIZE 512 + +/* + * Depending on the usecase, the SD card initialization could be done at the + * application level, if it is the case define the flag below to disable + * the BSP_SD_Init() call in the SD_Initialize(). + */ + +/* #define DISABLE_SD_INIT */ + +/* Private variables ---------------------------------------------------------*/ +/* Disk status */ +static volatile DSTATUS Stat = STA_NOINIT; + +/* Private function prototypes -----------------------------------------------*/ +static DSTATUS SD_CheckStatus(BYTE lun); +DSTATUS SD_initialize (BYTE); +DSTATUS SD_status (BYTE); +DRESULT SD_read (BYTE, BYTE*, DWORD, UINT); +#if _USE_WRITE == 1 + DRESULT SD_write (BYTE, const BYTE*, DWORD, UINT); +#endif /* _USE_WRITE == 1 */ +#if _USE_IOCTL == 1 + DRESULT SD_ioctl (BYTE, BYTE, void*); +#endif /* _USE_IOCTL == 1 */ + +const Diskio_drvTypeDef SD_Driver = +{ + SD_initialize, + SD_status, + SD_read, +#if _USE_WRITE == 1 + SD_write, +#endif /* _USE_WRITE == 1 */ + +#if _USE_IOCTL == 1 + SD_ioctl, +#endif /* _USE_IOCTL == 1 */ +}; + +/* Private functions ---------------------------------------------------------*/ +static DSTATUS SD_CheckStatus(BYTE lun) +{ + Stat = STA_NOINIT; + + if(BSP_SD_GetCardState() == MSD_OK) + { + Stat &= ~STA_NOINIT; + } + + return Stat; +} + +/** + * @brief Initializes a Drive + * @param lun : not used + * @retval DSTATUS: Operation status + */ +DSTATUS SD_initialize(BYTE lun) +{ + Stat = STA_NOINIT; +#if !defined(DISABLE_SD_INIT) + + if(BSP_SD_Init() == MSD_OK) + { + Stat = SD_CheckStatus(lun); + } + +#else + Stat = SD_CheckStatus(lun); +#endif + return Stat; +} + +/** + * @brief Gets Disk Status + * @param lun : not used + * @retval DSTATUS: Operation status + */ +DSTATUS SD_status(BYTE lun) +{ + return SD_CheckStatus(lun); +} + +/** + * @brief Reads Sector(s) + * @param lun : not used + * @param *buff: Data buffer to store read data + * @param sector: Sector address (LBA) + * @param count: Number of sectors to read (1..128) + * @retval DRESULT: Operation result + */ +DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count) +{ + DRESULT res = RES_ERROR; + + if(BSP_SD_ReadBlocks((uint32_t*)buff, + (uint32_t) (sector), + count, SD_TIMEOUT) == MSD_OK) + { + /* wait until the read operation is finished */ + while(BSP_SD_GetCardState()!= MSD_OK) + { + } + res = RES_OK; + } + + return res; +} + +/** + * @brief Writes Sector(s) + * @param lun : not used + * @param *buff: Data to be written + * @param sector: Sector address (LBA) + * @param count: Number of sectors to write (1..128) + * @retval DRESULT: Operation result + */ +#if _USE_WRITE == 1 +DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count) +{ + DRESULT res = RES_ERROR; + + if(BSP_SD_WriteBlocks((uint32_t*)buff, + (uint32_t)(sector), + count, SD_TIMEOUT) == MSD_OK) + { + /* wait until the Write operation is finished */ + while(BSP_SD_GetCardState() != MSD_OK) + { + } + res = RES_OK; + } + + return res; +} +#endif /* _USE_WRITE == 1 */ + +/** + * @brief I/O control operation + * @param lun : not used + * @param cmd: Control code + * @param *buff: Buffer to send/receive control data + * @retval DRESULT: Operation result + */ +#if _USE_IOCTL == 1 +DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff) +{ + DRESULT res = RES_ERROR; + BSP_SD_CardInfo CardInfo; + + if (Stat & STA_NOINIT) return RES_NOTRDY; + + switch (cmd) + { + /* Make sure that no pending write process */ + case CTRL_SYNC : + res = RES_OK; + break; + + /* Get number of sectors on the disk (DWORD) */ + case GET_SECTOR_COUNT : + BSP_SD_GetCardInfo(&CardInfo); + *(DWORD*)buff = CardInfo.LogBlockNbr; + res = RES_OK; + break; + + /* Get R/W sector size (WORD) */ + case GET_SECTOR_SIZE : + BSP_SD_GetCardInfo(&CardInfo); + *(WORD*)buff = CardInfo.LogBlockSize; + res = RES_OK; + break; + + /* Get erase block size in unit of sector (DWORD) */ + case GET_BLOCK_SIZE : + BSP_SD_GetCardInfo(&CardInfo); + *(DWORD*)buff = CardInfo.LogBlockSize / SD_DEFAULT_BLOCK_SIZE; + res = RES_OK; + break; + + default: + res = RES_PARERR; + } + + return res; +} +#endif /* _USE_IOCTL == 1 */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/port_stm32f7/common/fatfs/drivers/sd_diskio.h b/src/port_stm32f7/common/fatfs/drivers/sd_diskio.h new file mode 100644 index 00000000..ab4a3452 --- /dev/null +++ b/src/port_stm32f7/common/fatfs/drivers/sd_diskio.h @@ -0,0 +1,31 @@ +/** + ****************************************************************************** + * @file sd_diskio_tempalte.h + * @author MCD Application Team + * @brief Header for sd_diskio_template.c module.This file needs to be + customized then copied under the application project + ****************************************************************************** + * @attention + * + * Copyright (c) 2017 STMicroelectronics. All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** +**/ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __SD_DISKIO_H +#define __SD_DISKIO_H + +/* Includes ------------------------------------------------------------------*/ +#include "common.h" + +extern const Diskio_drvTypeDef SD_Driver; + +#endif /* __SD_DISKIO_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/port_stm32f7/common/fatfs/ff.c b/src/port_stm32f7/common/fatfs/ff.c new file mode 100644 index 00000000..b0bd4366 --- /dev/null +++ b/src/port_stm32f7/common/fatfs/ff.c @@ -0,0 +1,6140 @@ +/*----------------------------------------------------------------------------/ +/ FatFs - Generic FAT file system module R0.12c / +/-----------------------------------------------------------------------------/ +/ +/ Copyright (C) 2017, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: +/ +/ 1. Redistributions of source code must retain the above copyright notice, +/ this condition and the following disclaimer. +/ +/ This software is provided by the copyright holder and contributors "AS IS" +/ and any warranties related to this software are DISCLAIMED. +/ The copyright owner or contributors be NOT LIABLE for any damages caused +/ by use of this software. +/----------------------------------------------------------------------------*/ + + +#include "ff.h" /* Declarations of FatFs API */ +#include "diskio.h" /* Declarations of device I/O functions */ + + +/*-------------------------------------------------------------------------- + + Module Private Definitions + +---------------------------------------------------------------------------*/ + +#if _FATFS != 68300 /* Revision ID */ +#error Wrong include file (ff.h). +#endif + + +/* DBCS code ranges and SBCS upper conversion tables */ + +#if _CODE_PAGE == 932 /* Japanese Shift-JIS */ +#define _DF1S 0x81 /* DBC 1st byte range 1 start */ +#define _DF1E 0x9F /* DBC 1st byte range 1 end */ +#define _DF2S 0xE0 /* DBC 1st byte range 2 start */ +#define _DF2E 0xFC /* DBC 1st byte range 2 end */ +#define _DS1S 0x40 /* DBC 2nd byte range 1 start */ +#define _DS1E 0x7E /* DBC 2nd byte range 1 end */ +#define _DS2S 0x80 /* DBC 2nd byte range 2 start */ +#define _DS2E 0xFC /* DBC 2nd byte range 2 end */ + +#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0x80 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 949 /* Korean */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x41 +#define _DS1E 0x5A +#define _DS2S 0x61 +#define _DS2E 0x7A +#define _DS3S 0x81 +#define _DS3E 0xFE + +#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ +#define _DF1S 0x81 +#define _DF1E 0xFE +#define _DS1S 0x40 +#define _DS1E 0x7E +#define _DS2S 0xA1 +#define _DS2E 0xFE + +#elif _CODE_PAGE == 437 /* U.S. */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 720 /* Arabic */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 737 /* Greek */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ + 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 771 /* KBL */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDC,0xDE,0xDE, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF} + +#elif _CODE_PAGE == 775 /* Baltic */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 850 /* Latin 1 */ +#define _DF1S 0 +#define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \ + 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \ + 0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 852 /* Latin 2 */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \ + 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} + +#elif _CODE_PAGE == 855 /* Cyrillic */ +#define _DF1S 0 +#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \ + 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ + 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ + 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \ + 0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 857 /* Turkish */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ + 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 860 /* Portuguese */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \ + 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 861 /* Icelandic */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ + 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 862 /* Hebrew */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 863 /* Canadian-French */ +#define _DF1S 0 +#define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \ + 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \ + 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 864 /* Arabic */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 865 /* Nordic */ +#define _DF1S 0 +#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \ + 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \ + 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 866 /* Russian */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ + 0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} + +#elif _CODE_PAGE == 869 /* Greek 2 */ +#define _DF1S 0 +#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \ + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \ + 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \ + 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ + 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \ + 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \ + 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \ + 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF} + +#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ +#if _USE_LFN != 0 +#error Cannot enable LFN without valid code page. +#endif +#define _DF1S 0 + +#else +#error Unknown code page + +#endif + + +/* Character code support macros */ +#define IsUpper(c) (((c)>='A')&&((c)<='Z')) +#define IsLower(c) (((c)>='a')&&((c)<='z')) +#define IsDigit(c) (((c)>='0')&&((c)<='9')) + +#if _DF1S != 0 /* Code page is DBCS */ + +#ifdef _DF2S /* Two 1st byte areas */ +#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) +#else /* One 1st byte area */ +#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) +#endif + +#ifdef _DS3S /* Three 2nd byte areas */ +#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E)) +#else /* Two 2nd byte areas */ +#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E)) +#endif + +#else /* Code page is SBCS */ + +#define IsDBCS1(c) 0 +#define IsDBCS2(c) 0 + +#endif /* _DF1S */ + + +/* Additional file attribute bits for internal use */ +#define AM_VOL 0x08 /* Volume label */ +#define AM_LFN 0x0F /* LFN entry */ +#define AM_MASK 0x3F /* Mask of defined bits */ + + +/* Additional file access control and file status flags for internal use */ +#define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ +#define FA_MODIFIED 0x40 /* File has been modified */ +#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ + + +/* Name status flags in fn[] */ +#define NSFLAG 11 /* Index of the name status byte */ +#define NS_LOSS 0x01 /* Out of 8.3 format */ +#define NS_LFN 0x02 /* Force to create LFN entry */ +#define NS_LAST 0x04 /* Last segment */ +#define NS_BODY 0x08 /* Lower case flag (body) */ +#define NS_EXT 0x10 /* Lower case flag (ext) */ +#define NS_DOT 0x20 /* Dot entry */ +#define NS_NOLFN 0x40 /* Do not find LFN */ +#define NS_NONAME 0x80 /* Not followed */ + + +/* Limits and boundaries */ +#define MAX_DIR 0x200000 /* Max size of FAT directory */ +#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ +#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but correct for real DOS/Windows behavior) */ +#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but correct for real DOS/Windows behavior) */ +#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ +#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ + + +/* FatFs refers the FAT structure as simple byte array instead of structure member +/ because the C structure is not binary compatible between different platforms */ + +#define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ +#define BS_OEMName 3 /* OEM name (8-byte) */ +#define BPB_BytsPerSec 11 /* Sector size [byte] (WORD) */ +#define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */ +#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (WORD) */ +#define BPB_NumFATs 16 /* Number of FATs (BYTE) */ +#define BPB_RootEntCnt 17 /* Size of root directory area for FAT12/16 [entry] (WORD) */ +#define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */ +#define BPB_Media 21 /* Media descriptor byte (BYTE) */ +#define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */ +#define BPB_SecPerTrk 24 /* Track size for int13h [sector] (WORD) */ +#define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */ +#define BPB_HiddSec 28 /* Volume offset from top of the drive (DWORD) */ +#define BPB_TotSec32 32 /* Volume size (32-bit) [sector] (DWORD) */ +#define BS_DrvNum 36 /* Physical drive number for int13h (BYTE) */ +#define BS_NTres 37 /* Error flag (BYTE) */ +#define BS_BootSig 38 /* Extended boot signature (BYTE) */ +#define BS_VolID 39 /* Volume serial number (DWORD) */ +#define BS_VolLab 43 /* Volume label string (8-byte) */ +#define BS_FilSysType 54 /* File system type string (8-byte) */ +#define BS_BootCode 62 /* Boot code (448-byte) */ +#define BS_55AA 510 /* Signature word (WORD) */ + +#define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */ +#define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */ +#define BPB_FSVer32 42 /* FAT32: File system version (WORD) */ +#define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */ +#define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */ +#define BPB_BkBootSec32 50 /* FAT32: Offset of backup boot sector (WORD) */ +#define BS_DrvNum32 64 /* FAT32: Physical drive number for int13h (BYTE) */ +#define BS_NTres32 65 /* FAT32: Error flag (BYTE) */ +#define BS_BootSig32 66 /* FAT32: Extended boot signature (BYTE) */ +#define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */ +#define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */ +#define BS_FilSysType32 82 /* FAT32: File system type string (8-byte) */ +#define BS_BootCode32 90 /* FAT32: Boot code (420-byte) */ + +#define BPB_ZeroedEx 11 /* exFAT: MBZ field (53-byte) */ +#define BPB_VolOfsEx 64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */ +#define BPB_TotSecEx 72 /* exFAT: Volume size [sector] (QWORD) */ +#define BPB_FatOfsEx 80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */ +#define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ +#define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ +#define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ +#define BPB_RootClusEx 96 /* exFAT: Root directory start cluster (DWORD) */ +#define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ +#define BPB_FSVerEx 104 /* exFAT: File system version (WORD) */ +#define BPB_VolFlagEx 106 /* exFAT: Volume flags (BYTE) */ +#define BPB_ActFatEx 107 /* exFAT: Active FAT flags (BYTE) */ +#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */ +#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */ +#define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ +#define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ +#define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ +#define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ +#define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ + +#define DIR_Name 0 /* Short file name (11-byte) */ +#define DIR_Attr 11 /* Attribute (BYTE) */ +#define DIR_NTres 12 /* Lower case flag (BYTE) */ +#define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ +#define DIR_CrtTime 14 /* Created time (DWORD) */ +#define DIR_LstAccDate 18 /* Last accessed date (WORD) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ +#define DIR_ModTime 22 /* Modified time (DWORD) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ +#define DIR_FileSize 28 /* File size (DWORD) */ +#define LDIR_Ord 0 /* LFN: LFN order and LLE flag (BYTE) */ +#define LDIR_Attr 11 /* LFN: LFN attribute (BYTE) */ +#define LDIR_Type 12 /* LFN: Entry type (BYTE) */ +#define LDIR_Chksum 13 /* LFN: Checksum of the SFN (BYTE) */ +#define LDIR_FstClusLO 26 /* LFN: MBZ field (WORD) */ +#define XDIR_Type 0 /* exFAT: Type of exFAT directory entry (BYTE) */ +#define XDIR_NumLabel 1 /* exFAT: Number of volume label characters (BYTE) */ +#define XDIR_Label 2 /* exFAT: Volume label (11-WORD) */ +#define XDIR_CaseSum 4 /* exFAT: Sum of case conversion table (DWORD) */ +#define XDIR_NumSec 1 /* exFAT: Number of secondary entries (BYTE) */ +#define XDIR_SetSum 2 /* exFAT: Sum of the set of directory entries (WORD) */ +#define XDIR_Attr 4 /* exFAT: File attribute (WORD) */ +#define XDIR_CrtTime 8 /* exFAT: Created time (DWORD) */ +#define XDIR_ModTime 12 /* exFAT: Modified time (DWORD) */ +#define XDIR_AccTime 16 /* exFAT: Last accessed time (DWORD) */ +#define XDIR_CrtTime10 20 /* exFAT: Created time subsecond (BYTE) */ +#define XDIR_ModTime10 21 /* exFAT: Modified time subsecond (BYTE) */ +#define XDIR_CrtTZ 22 /* exFAT: Created timezone (BYTE) */ +#define XDIR_ModTZ 23 /* exFAT: Modified timezone (BYTE) */ +#define XDIR_AccTZ 24 /* exFAT: Last accessed timezone (BYTE) */ +#define XDIR_GenFlags 33 /* exFAT: General secondary flags (WORD) */ +#define XDIR_NumName 35 /* exFAT: Number of file name characters (BYTE) */ +#define XDIR_NameHash 36 /* exFAT: Hash of file name (WORD) */ +#define XDIR_ValidFileSize 40 /* exFAT: Valid file size (QWORD) */ +#define XDIR_FstClus 52 /* exFAT: First cluster of the file data (DWORD) */ +#define XDIR_FileSize 56 /* exFAT: File/Directory size (QWORD) */ + +#define SZDIRE 32 /* Size of a directory entry */ +#define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ +#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ +#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ + +#define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ +#define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ +#define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ +#define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */ + +#define MBR_Table 446 /* MBR: Offset of partition table in the MBR */ +#define SZ_PTE 16 /* MBR: Size of a partition table entry */ +#define PTE_Boot 0 /* MBR PTE: Boot indicator */ +#define PTE_StHead 1 /* MBR PTE: Start head */ +#define PTE_StSec 2 /* MBR PTE: Start sector */ +#define PTE_StCyl 3 /* MBR PTE: Start cylinder */ +#define PTE_System 4 /* MBR PTE: System ID */ +#define PTE_EdHead 5 /* MBR PTE: End head */ +#define PTE_EdSec 6 /* MBR PTE: End sector */ +#define PTE_EdCyl 7 /* MBR PTE: End cylinder */ +#define PTE_StLba 8 /* MBR PTE: Start in LBA */ +#define PTE_SizLba 12 /* MBR PTE: Size in LBA */ + + +/* Post process after fatal error on file operation */ +#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } + + +/* Reentrancy related */ +#if _FS_REENTRANT +#if _USE_LFN == 1 +#error Static LFN work area cannot be used at thread-safe configuration +#endif +#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } +#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#else +#define ENTER_FF(fs) +#define LEAVE_FF(fs, res) return res +#endif + + +/* Definitions of volume - partition conversion */ +#if _MULTI_PARTITION +#define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number */ +#define LD2PT(vol) VolToPart[vol].pt /* Get partition index */ +#else +#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ +#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ +#endif + + +/* Definitions of sector size */ +#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096) +#error Wrong sector size configuration +#endif +#if _MAX_SS == _MIN_SS +#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */ +#else +#define SS(fs) ((fs)->ssize) /* Variable sector size */ +#endif + + +/* Timestamp */ +#if _FS_NORTC == 1 +#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 +#error Invalid _FS_NORTC settings +#endif +#define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16) +#else +#define GET_FATTIME() get_fattime() +#endif + + +/* File lock controls */ +#if _FS_LOCK != 0 +#if _FS_READONLY +#error _FS_LOCK must be 0 at read-only configuration +#endif +typedef struct { + FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ + DWORD clu; /* Object ID 2, containing directory (0:root) */ + DWORD ofs; /* Object ID 3, offset in the directory */ + WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ +} FILESEM; +#endif + + + + + +/*-------------------------------------------------------------------------- + + Module Private Work Area + +---------------------------------------------------------------------------*/ + +/* Remark: Variables defined here without initial value shall be guaranteed +/ zero/null at start-up. If not, the linker option or start-up routine is +/ not compliance with C standard. */ + +#if _VOLUMES < 1 || _VOLUMES > 10 +#error Wrong _VOLUMES setting +#endif +static FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ +static WORD Fsid; /* File system mount ID */ + +#if _FS_RPATH != 0 && _VOLUMES >= 2 +static BYTE CurrVol; /* Current drive */ +#endif + +#if _FS_LOCK != 0 +static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */ +#endif + +#if _USE_LFN == 0 /* Non-LFN configuration */ +#define DEF_NAMBUF +#define INIT_NAMBUF(fs) +#define FREE_NAMBUF() + +#else /* LFN configuration */ +#if _MAX_LFN < 12 || _MAX_LFN > 255 +#error Wrong _MAX_LFN value +#endif +#define MAXDIRB(nc) ((nc + 44U) / 15 * SZDIRE) + +#if _USE_LFN == 1 /* LFN enabled with static working buffer */ +#if _FS_EXFAT +static BYTE DirBuf[MAXDIRB(_MAX_LFN)]; /* Directory entry block scratchpad buffer */ +#endif +static WCHAR LfnBuf[_MAX_LFN + 1]; /* LFN enabled with static working buffer */ +#define DEF_NAMBUF +#define INIT_NAMBUF(fs) +#define FREE_NAMBUF() + +#elif _USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ +#if _FS_EXFAT +#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; BYTE dbuf[MAXDIRB(_MAX_LFN)]; +#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } +#define FREE_NAMBUF() +#else +#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; +#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; } +#define FREE_NAMBUF() +#endif + +#elif _USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ +#if _FS_EXFAT +#define DEF_NAMBUF WCHAR *lfn; +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2 + MAXDIRB(_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+_MAX_LFN+1); } +#define FREE_NAMBUF() ff_memfree(lfn) +#else +#define DEF_NAMBUF WCHAR *lfn; +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; } +#define FREE_NAMBUF() ff_memfree(lfn) +#endif + +#else +#error Wrong _USE_LFN setting + +#endif +#endif /* else _USE_LFN == 0 */ + +#ifdef _EXCVT +static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended characters */ +#endif + + + + + + +/*-------------------------------------------------------------------------- + + Module Private Functions + +---------------------------------------------------------------------------*/ + + +/*-----------------------------------------------------------------------*/ +/* Load/Store multi-byte word in the FAT structure */ +/*-----------------------------------------------------------------------*/ + +static +WORD ld_word (const BYTE* ptr) /* Load a 2-byte little-endian word */ +{ + WORD rv; + + rv = ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +static +DWORD ld_dword (const BYTE* ptr) /* Load a 4-byte little-endian word */ +{ + DWORD rv; + + rv = ptr[3]; + rv = rv << 8 | ptr[2]; + rv = rv << 8 | ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} + +#if _FS_EXFAT +static +QWORD ld_qword (const BYTE* ptr) /* Load an 8-byte little-endian word */ +{ + QWORD rv; + + rv = ptr[7]; + rv = rv << 8 | ptr[6]; + rv = rv << 8 | ptr[5]; + rv = rv << 8 | ptr[4]; + rv = rv << 8 | ptr[3]; + rv = rv << 8 | ptr[2]; + rv = rv << 8 | ptr[1]; + rv = rv << 8 | ptr[0]; + return rv; +} +#endif + +#if !_FS_READONLY +static +void st_word (BYTE* ptr, WORD val) /* Store a 2-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} + +static +void st_dword (BYTE* ptr, DWORD val) /* Store a 4-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} + +#if _FS_EXFAT +static +void st_qword (BYTE* ptr, QWORD val) /* Store an 8-byte word in little-endian */ +{ + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; val >>= 8; + *ptr++ = (BYTE)val; +} +#endif +#endif /* !_FS_READONLY */ + + + +/*-----------------------------------------------------------------------*/ +/* String functions */ +/*-----------------------------------------------------------------------*/ + +/* Copy memory to memory */ +static +void mem_cpy (void* dst, const void* src, UINT cnt) { + BYTE *d = (BYTE*)dst; + const BYTE *s = (const BYTE*)src; + + if (cnt) { + do { + *d++ = *s++; + } while (--cnt); + } +} + +/* Fill memory block */ +static +void mem_set (void* dst, int val, UINT cnt) { + BYTE *d = (BYTE*)dst; + + do { + *d++ = (BYTE)val; + } while (--cnt); +} + +/* Compare memory block */ +static +int mem_cmp (const void* dst, const void* src, UINT cnt) { /* ZR:same, NZ:different */ + const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src; + int r = 0; + + do { + r = *d++ - *s++; + } while (--cnt && r == 0); + + return r; +} + +/* Check if chr is contained in the string */ +static +int chk_chr (const char* str, int chr) { /* NZ:contained, ZR:not contained */ + while (*str && *str != chr) str++; + return *str; +} + + + + +#if _FS_REENTRANT +/*-----------------------------------------------------------------------*/ +/* Request/Release grant to access the volume */ +/*-----------------------------------------------------------------------*/ +static +int lock_fs ( + FATFS* fs /* File system object */ +) +{ + return (fs && ff_req_grant(fs->sobj)) ? 1 : 0; +} + + +static +void unlock_fs ( + FATFS* fs, /* File system object */ + FRESULT res /* Result code to be returned */ +) +{ + if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { + ff_rel_grant(fs->sobj); + } +} + +#endif + + + +#if _FS_LOCK != 0 +/*-----------------------------------------------------------------------*/ +/* File lock control functions */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT chk_lock ( /* Check if the file can be accessed */ + DIR* dp, /* Directory object pointing the file to be checked */ + int acc /* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */ +) +{ + UINT i, be; + + /* Search file semaphore table */ + for (i = be = 0; i < _FS_LOCK; i++) { + if (Files[i].fs) { /* Existing entry */ + if (Files[i].fs == dp->obj.fs && /* Check if the object matched with an open object */ + Files[i].clu == dp->obj.sclust && + Files[i].ofs == dp->dptr) break; + } else { /* Blank entry */ + be = 1; + } + } + if (i == _FS_LOCK) { /* The object is not opened */ + return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new object? */ + } + + /* The object has been opened. Reject any open against writing file and all write mode open */ + return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK; +} + + +static +int enq_lock (void) /* Check if an entry is available for a new object */ +{ + UINT i; + + for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; + return (i == _FS_LOCK) ? 0 : 1; +} + + +static +UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ + DIR* dp, /* Directory object pointing the file to register or increment */ + int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ +) +{ + UINT i; + + + for (i = 0; i < _FS_LOCK; i++) { /* Find the object */ + if (Files[i].fs == dp->obj.fs && + Files[i].clu == dp->obj.sclust && + Files[i].ofs == dp->dptr) break; + } + + if (i == _FS_LOCK) { /* Not opened. Register it as new. */ + for (i = 0; i < _FS_LOCK && Files[i].fs; i++) ; + if (i == _FS_LOCK) return 0; /* No free entry to register (int err) */ + Files[i].fs = dp->obj.fs; + Files[i].clu = dp->obj.sclust; + Files[i].ofs = dp->dptr; + Files[i].ctr = 0; + } + + if (acc && Files[i].ctr) return 0; /* Access violation (int err) */ + + Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */ + + return i + 1; +} + + +static +FRESULT dec_lock ( /* Decrement object open counter */ + UINT i /* Semaphore index (1..) */ +) +{ + WORD n; + FRESULT res; + + + if (--i < _FS_LOCK) { /* Shift index number origin from 0 */ + n = Files[i].ctr; + if (n == 0x100) n = 0; /* If write mode open, delete the entry */ + if (n > 0) n--; /* Decrement read mode open count */ + Files[i].ctr = n; + if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ + res = FR_OK; + } else { + res = FR_INT_ERR; /* Invalid index nunber */ + } + return res; +} + + +static +void clear_lock ( /* Clear lock entries of the volume */ + FATFS *fs +) +{ + UINT i; + + for (i = 0; i < _FS_LOCK; i++) { + if (Files[i].fs == fs) Files[i].fs = 0; + } +} + +#endif /* _FS_LOCK != 0 */ + + + +/*-----------------------------------------------------------------------*/ +/* Move/Flush disk access window in the file system object */ +/*-----------------------------------------------------------------------*/ +#if !_FS_READONLY +static +FRESULT sync_window ( /* Returns FR_OK or FR_DISK_ERROR */ + FATFS* fs /* File system object */ +) +{ + DWORD wsect; + UINT nf; + FRESULT res = FR_OK; + + + if (fs->wflag) { /* Write back the sector if it is dirty */ + wsect = fs->winsect; /* Current sector number */ + if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) { + res = FR_DISK_ERR; + } else { + fs->wflag = 0; + if (wsect - fs->fatbase < fs->fsize) { /* Is it in the FAT area? */ + for (nf = fs->n_fats; nf >= 2; nf--) { /* Reflect the change to all FAT copies */ + wsect += fs->fsize; + disk_write(fs->drv, fs->win, wsect, 1); + } + } + } + } + return res; +} +#endif + + +static +FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERROR */ + FATFS* fs, /* File system object */ + DWORD sector /* Sector number to make appearance in the fs->win[] */ +) +{ + FRESULT res = FR_OK; + + + if (sector != fs->winsect) { /* Window offset changed? */ +#if !_FS_READONLY + res = sync_window(fs); /* Write-back changes */ +#endif + if (res == FR_OK) { /* Fill sector window with new data */ + if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) { + sector = 0xFFFFFFFF; /* Invalidate window if data is not reliable */ + res = FR_DISK_ERR; + } + fs->winsect = sector; + } + } + return res; +} + + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Synchronize file system and strage device */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */ + FATFS* fs /* File system object */ +) +{ + FRESULT res; + + + res = sync_window(fs); + if (res == FR_OK) { + /* Update FSInfo sector if needed */ + if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { + /* Create FSInfo structure */ + mem_set(fs->win, 0, SS(fs)); + st_word(fs->win + BS_55AA, 0xAA55); + st_dword(fs->win + FSI_LeadSig, 0x41615252); + st_dword(fs->win + FSI_StrucSig, 0x61417272); + st_dword(fs->win + FSI_Free_Count, fs->free_clst); + st_dword(fs->win + FSI_Nxt_Free, fs->last_clst); + /* Write it into the FSInfo sector */ + fs->winsect = fs->volbase + 1; + disk_write(fs->drv, fs->win, fs->winsect, 1); + fs->fsi_flag = 0; + } + /* Make sure that no pending write process in the physical drive */ + if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK) res = FR_DISK_ERR; + } + + return res; +} + +#endif + + + +/*-----------------------------------------------------------------------*/ +/* Get sector# from cluster# */ +/*-----------------------------------------------------------------------*/ + +static +DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */ + FATFS* fs, /* File system object */ + DWORD clst /* Cluster# to be converted */ +) +{ + clst -= 2; + if (clst >= fs->n_fatent - 2) return 0; /* Invalid cluster# */ + return clst * fs->csize + fs->database; +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT access - Read value of a FAT entry */ +/*-----------------------------------------------------------------------*/ + +static +DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluster status */ + _FDID* obj, /* Corresponding object */ + DWORD clst /* Cluster number to get the value */ +) +{ + UINT wc, bc; + DWORD val; + FATFS *fs = obj->fs; + + + if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */ + val = 1; /* Internal error */ + + } else { + val = 0xFFFFFFFF; /* Default value falls on disk error */ + + switch (fs->fs_type) { + case FS_FAT12 : + bc = (UINT)clst; bc += bc / 2; + if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; + wc = fs->win[bc++ % SS(fs)]; + if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK) break; + wc |= fs->win[bc % SS(fs)] << 8; + val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF); + break; + + case FS_FAT16 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break; + val = ld_word(fs->win + clst * 2 % SS(fs)); + break; + + case FS_FAT32 : + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF; + break; +#if _FS_EXFAT + case FS_EXFAT : + if (obj->objsize) { + DWORD cofs = clst - obj->sclust; /* Offset from start cluster */ + DWORD clen = (DWORD)((obj->objsize - 1) / SS(fs)) / fs->csize; /* Number of clusters - 1 */ + + if (obj->stat == 2) { /* Is there no valid chain on the FAT? */ + if (cofs <= clen) { + val = (cofs == clen) ? 0x7FFFFFFF : clst + 1; /* Generate the value */ + break; + } + } + if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the 1st fragment? */ + val = clst + 1; /* Generate the value */ + break; + } + if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ + if (obj->n_frag != 0) { /* Is it on the growing edge? */ + val = 0x7FFFFFFF; /* Generate EOC */ + } else { + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + } + break; + } + } + /* go to default */ +#endif + default: + val = 1; /* Internal error */ + } + } + + return val; +} + + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* FAT access - Change value of a FAT entry */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ + FATFS* fs, /* Corresponding file system object */ + DWORD clst, /* FAT index number (cluster number) to be changed */ + DWORD val /* New value to be set to the entry */ +) +{ + UINT bc; + BYTE *p; + FRESULT res = FR_INT_ERR; + + if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ + switch (fs->fs_type) { + case FS_FAT12 : /* Bitfield items */ + bc = (UINT)clst; bc += bc / 2; + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) break; + p = fs->win + bc++ % SS(fs); + *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val; + fs->wflag = 1; + res = move_window(fs, fs->fatbase + (bc / SS(fs))); + if (res != FR_OK) break; + p = fs->win + bc % SS(fs); + *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F)); + fs->wflag = 1; + break; + + case FS_FAT16 : /* WORD aligned items */ + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))); + if (res != FR_OK) break; + st_word(fs->win + clst * 2 % SS(fs), (WORD)val); + fs->wflag = 1; + break; + + case FS_FAT32 : /* DWORD aligned items */ +#if _FS_EXFAT + case FS_EXFAT : +#endif + res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))); + if (res != FR_OK) break; + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000); + } + st_dword(fs->win + clst * 4 % SS(fs), val); + fs->wflag = 1; + break; + } + } + return res; +} + +#endif /* !_FS_READONLY */ + + + + +#if _FS_EXFAT && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* exFAT: Accessing FAT and Allocation Bitmap */ +/*-----------------------------------------------------------------------*/ + +/*--------------------------------------*/ +/* Find a contiguous free cluster block */ +/*--------------------------------------*/ + +static +DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */ + FATFS* fs, /* File system object */ + DWORD clst, /* Cluster number to scan from */ + DWORD ncl /* Number of contiguous clusters to find (1..) */ +) +{ + BYTE bm, bv; + UINT i; + DWORD val, scl, ctr; + + + clst -= 2; /* The first bit in the bitmap corresponds to cluster #2 */ + if (clst >= fs->n_fatent - 2) clst = 0; + scl = val = clst; ctr = 0; + for (;;) { + if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */ + i = val / 8 % SS(fs); bm = 1 << (val % 8); + do { + do { + bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ + if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ + val = 0; bm = 0; i = SS(fs); + } + if (!bv) { /* Is it a free cluster? */ + if (++ctr == ncl) return scl + 2; /* Check if run length is sufficient for required */ + } else { + scl = val; ctr = 0; /* Encountered a cluster in-use, restart to scan */ + } + if (val == clst) return 0; /* All cluster scanned? */ + } while (bm); + bm = 1; + } while (++i < SS(fs)); + } +} + + +/*----------------------------------------*/ +/* Set/Clear a block of allocation bitmap */ +/*----------------------------------------*/ + +static +FRESULT change_bitmap ( + FATFS* fs, /* File system object */ + DWORD clst, /* Cluster number to change from */ + DWORD ncl, /* Number of clusters to be changed */ + int bv /* bit value to be set (0 or 1) */ +) +{ + BYTE bm; + UINT i; + DWORD sect; + + clst -= 2; /* The first bit corresponds to cluster #2 */ + sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */ + i = clst / 8 % SS(fs); /* Byte offset in the sector */ + bm = 1 << (clst % 8); /* Bit mask in the byte */ + for (;;) { + if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR; + do { + do { + if (bv == (int)((fs->win[i] & bm) != 0)) return FR_INT_ERR; /* Is the bit expected value? */ + fs->win[i] ^= bm; /* Flip the bit */ + fs->wflag = 1; + if (--ncl == 0) return FR_OK; /* All bits processed? */ + } while (bm <<= 1); /* Next bit */ + bm = 1; + } while (++i < SS(fs)); /* Next byte */ + i = 0; + } +} + + +/*---------------------------------------------*/ +/* Fill the first fragment of the FAT chain */ +/*---------------------------------------------*/ + +static +FRESULT fill_first_frag ( + _FDID* obj /* Pointer to the corresponding object */ +) +{ + FRESULT res; + DWORD cl, n; + + if (obj->stat == 3) { /* Has the object been changed 'fragmented'? */ + for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */ + res = put_fat(obj->fs, cl, cl + 1); + if (res != FR_OK) return res; + } + obj->stat = 0; /* Change status 'FAT chain is valid' */ + } + return FR_OK; +} + + +/*---------------------------------------------*/ +/* Fill the last fragment of the FAT chain */ +/*---------------------------------------------*/ + +static +FRESULT fill_last_frag ( + _FDID* obj, /* Pointer to the corresponding object */ + DWORD lcl, /* Last cluster of the fragment */ + DWORD term /* Value to set the last FAT entry */ +) +{ + FRESULT res; + + while (obj->n_frag > 0) { /* Create the last chain on the FAT */ + res = put_fat(obj->fs, lcl - obj->n_frag + 1, (obj->n_frag > 1) ? lcl - obj->n_frag + 2 : term); + if (res != FR_OK) return res; + obj->n_frag--; + } + return FR_OK; +} + +#endif /* _FS_EXFAT && !_FS_READONLY */ + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* FAT handling - Remove a cluster chain */ +/*-----------------------------------------------------------------------*/ +static +FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ + _FDID* obj, /* Corresponding object */ + DWORD clst, /* Cluster to remove a chain from */ + DWORD pclst /* Previous cluster of clst (0:an entire chain) */ +) +{ + FRESULT res = FR_OK; + DWORD nxt; + FATFS *fs = obj->fs; +#if _FS_EXFAT || _USE_TRIM + DWORD scl = clst, ecl = clst; +#endif +#if _USE_TRIM + DWORD rt[2]; +#endif + + if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Check if in valid range */ + + /* Mark the previous cluster 'EOC' on the FAT if it exists */ + if (pclst && (!_FS_EXFAT || fs->fs_type != FS_EXFAT || obj->stat != 2)) { + res = put_fat(fs, pclst, 0xFFFFFFFF); + if (res != FR_OK) return res; + } + + /* Remove the chain */ + do { + nxt = get_fat(obj, clst); /* Get cluster status */ + if (nxt == 0) break; /* Empty cluster? */ + if (nxt == 1) return FR_INT_ERR; /* Internal error? */ + if (nxt == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error? */ + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */ + if (res != FR_OK) return res; + } + if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ + fs->free_clst++; + fs->fsi_flag |= 1; + } +#if _FS_EXFAT || _USE_TRIM + if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ + ecl = nxt; + } else { /* End of contiguous cluster block */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ + if (res != FR_OK) return res; + } +#endif +#if _USE_TRIM + rt[0] = clust2sect(fs, scl); /* Start sector */ + rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */ + disk_ioctl(fs->drv, CTRL_TRIM, rt); /* Inform device the block can be erased */ +#endif + scl = ecl = nxt; + } +#endif + clst = nxt; /* Next cluster */ + } while (clst < fs->n_fatent); /* Repeat while not the last link */ + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + if (pclst == 0) { /* Does the object have no chain? */ + obj->stat = 0; /* Change the object status 'initial' */ + } else { + if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Did the chain get contiguous? */ + obj->stat = 2; /* Change the object status 'contiguous' */ + } + } + } +#endif + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* FAT handling - Stretch a chain or Create a new chain */ +/*-----------------------------------------------------------------------*/ +static +DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ + _FDID* obj, /* Corresponding object */ + DWORD clst /* Cluster# to stretch, 0:Create a new chain */ +) +{ + DWORD cs, ncl, scl; + FRESULT res; + FATFS *fs = obj->fs; + + + if (clst == 0) { /* Create a new chain */ + scl = fs->last_clst; /* Get suggested cluster to start from */ + if (scl == 0 || scl >= fs->n_fatent) scl = 1; + } + else { /* Stretch current chain */ + cs = get_fat(obj, clst); /* Check the cluster status */ + if (cs < 2) return 1; /* Invalid FAT value */ + if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */ + if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ + scl = clst; + } + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */ + if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */ + res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */ + if (res == FR_INT_ERR) return 1; + if (res == FR_DISK_ERR) return 0xFFFFFFFF; + if (clst == 0) { /* Is it a new chain? */ + obj->stat = 2; /* Set status 'contiguous' */ + } else { /* It is a stretched chain */ + if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ + obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ + obj->stat = 3; /* Change status 'just fragmented' */ + } + } + if (obj->stat != 2) { /* Is the file non-contiguous? */ + if (ncl == clst + 1) { /* Is the cluster next to previous one? */ + obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2; /* Increment size of last framgent */ + } else { /* New fragment */ + if (obj->n_frag == 0) obj->n_frag = 1; + res = fill_last_frag(obj, clst, ncl); /* Fill last fragment on the FAT and link it to new one */ + if (res == FR_OK) obj->n_frag = 1; + } + } + } else +#endif + { /* On the FAT12/16/32 volume */ + ncl = scl; /* Start cluster */ + for (;;) { + ncl++; /* Next cluster */ + if (ncl >= fs->n_fatent) { /* Check wrap-around */ + ncl = 2; + if (ncl > scl) return 0; /* No free cluster */ + } + cs = get_fat(obj, ncl); /* Get the cluster status */ + if (cs == 0) break; /* Found a free cluster */ + if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* An error occurred */ + if (ncl == scl) return 0; /* No free cluster */ + } + res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ + if (res == FR_OK && clst != 0) { + res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ + } + } + + if (res == FR_OK) { /* Update FSINFO if function succeeded. */ + fs->last_clst = ncl; + if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; + fs->fsi_flag |= 1; + } else { + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ + } + + return ncl; /* Return new cluster number or error status */ +} + +#endif /* !_FS_READONLY */ + + + + +#if _USE_FASTSEEK +/*-----------------------------------------------------------------------*/ +/* FAT handling - Convert offset into cluster with link map table */ +/*-----------------------------------------------------------------------*/ + +static +DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ + FIL* fp, /* Pointer to the file object */ + FSIZE_t ofs /* File offset to be converted to cluster# */ +) +{ + DWORD cl, ncl, *tbl; + FATFS *fs = fp->obj.fs; + + + tbl = fp->cltbl + 1; /* Top of CLMT */ + cl = (DWORD)(ofs / SS(fs) / fs->csize); /* Cluster order from top of the file */ + for (;;) { + ncl = *tbl++; /* Number of cluters in the fragment */ + if (ncl == 0) return 0; /* End of table? (error) */ + if (cl < ncl) break; /* In this fragment? */ + cl -= ncl; tbl++; /* Next fragment */ + } + return cl + *tbl; /* Return the cluster number */ +} + +#endif /* _USE_FASTSEEK */ + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Set directory index */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp, /* Pointer to directory object */ + DWORD ofs /* Offset of directory table */ +) +{ + DWORD csz, clst; + FATFS *fs = dp->obj.fs; + + + if (ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR) || ofs % SZDIRE) { /* Check range of offset and alignment */ + return FR_INT_ERR; + } + dp->dptr = ofs; /* Set current offset */ + clst = dp->obj.sclust; /* Table start cluster (0:root) */ + if (clst == 0 && fs->fs_type >= FS_FAT32) { /* Replace cluster# 0 with root cluster# */ + clst = fs->dirbase; + if (_FS_EXFAT) dp->obj.stat = 0; /* exFAT: Root dir has an FAT chain */ + } + + if (clst == 0) { /* Static table (root-directory in FAT12/16) */ + if (ofs / SZDIRE >= fs->n_rootdir) return FR_INT_ERR; /* Is index out of range? */ + dp->sect = fs->dirbase; + + } else { /* Dynamic table (sub-directory or root-directory in FAT32+) */ + csz = (DWORD)fs->csize * SS(fs); /* Bytes per cluster */ + while (ofs >= csz) { /* Follow cluster chain */ + clst = get_fat(&dp->obj, clst); /* Get next cluster */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst < 2 || clst >= fs->n_fatent) return FR_INT_ERR; /* Reached to end of table or internal error */ + ofs -= csz; + } + dp->sect = clust2sect(fs, clst); + } + dp->clust = clst; /* Current cluster# */ + if (!dp->sect) return FR_INT_ERR; + dp->sect += ofs / SS(fs); /* Sector# of the directory entry */ + dp->dir = fs->win + (ofs % SS(fs)); /* Pointer to the entry in the win[] */ + + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Move directory table index next */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ + DIR* dp, /* Pointer to the directory object */ + int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ +) +{ + DWORD ofs, clst; + FATFS *fs = dp->obj.fs; +#if !_FS_READONLY + UINT n; +#endif + + ofs = dp->dptr + SZDIRE; /* Next entry */ + if (!dp->sect || ofs >= (DWORD)((_FS_EXFAT && fs->fs_type == FS_EXFAT) ? MAX_DIR_EX : MAX_DIR)) return FR_NO_FILE; /* Report EOT when offset has reached max value */ + + if (ofs % SS(fs) == 0) { /* Sector changed? */ + dp->sect++; /* Next sector */ + + if (!dp->clust) { /* Static table */ + if (ofs / SZDIRE >= fs->n_rootdir) { /* Report EOT if it reached end of static table */ + dp->sect = 0; return FR_NO_FILE; + } + } + else { /* Dynamic table */ + if ((ofs / SS(fs) & (fs->csize - 1)) == 0) { /* Cluster changed? */ + clst = get_fat(&dp->obj, dp->clust); /* Get next cluster */ + if (clst <= 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + if (clst >= fs->n_fatent) { /* Reached end of dynamic table */ +#if !_FS_READONLY + if (!stretch) { /* If no stretch, report EOT */ + dp->sect = 0; return FR_NO_FILE; + } + clst = create_chain(&dp->obj, dp->clust); /* Allocate a cluster */ + if (clst == 0) return FR_DENIED; /* No free cluster */ + if (clst == 1) return FR_INT_ERR; /* Internal error */ + if (clst == 0xFFFFFFFF) return FR_DISK_ERR; /* Disk error */ + /* Clean-up the stretched table */ + if (_FS_EXFAT) dp->obj.stat |= 4; /* The directory needs to be updated */ + if (sync_window(fs) != FR_OK) return FR_DISK_ERR; /* Flush disk access window */ + mem_set(fs->win, 0, SS(fs)); /* Clear window buffer */ + for (n = 0, fs->winsect = clust2sect(fs, clst); n < fs->csize; n++, fs->winsect++) { /* Fill the new cluster with 0 */ + fs->wflag = 1; + if (sync_window(fs) != FR_OK) return FR_DISK_ERR; + } + fs->winsect -= n; /* Restore window offset */ +#else + if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */ + dp->sect = 0; return FR_NO_FILE; /* Report EOT */ +#endif + } + dp->clust = clst; /* Initialize data for new cluster */ + dp->sect = clust2sect(fs, clst); + } + } + } + dp->dptr = ofs; /* Current entry */ + dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */ + + return FR_OK; +} + + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Directory handling - Reserve a block of directory entries */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp, /* Pointer to the directory object */ + UINT nent /* Number of contiguous entries to allocate */ +) +{ + FRESULT res; + UINT n; + FATFS *fs = dp->obj.fs; + + + res = dir_sdi(dp, 0); + if (res == FR_OK) { + n = 0; + do { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; +#if _FS_EXFAT + if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) { +#else + if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) { +#endif + if (++n == nent) break; /* A block of contiguous free entries is found */ + } else { + n = 0; /* Not a blank entry. Restart to search */ + } + res = dir_next(dp, 1); + } while (res == FR_OK); /* Next entry with table stretch enabled */ + } + + if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */ + return res; +} + +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* FAT: Directory handling - Load/Store start cluster number */ +/*-----------------------------------------------------------------------*/ + +static +DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */ + FATFS* fs, /* Pointer to the fs object */ + const BYTE* dir /* Pointer to the key entry */ +) +{ + DWORD cl; + + cl = ld_word(dir + DIR_FstClusLO); + if (fs->fs_type == FS_FAT32) { + cl |= (DWORD)ld_word(dir + DIR_FstClusHI) << 16; + } + + return cl; +} + + +#if !_FS_READONLY +static +void st_clust ( + FATFS* fs, /* Pointer to the fs object */ + BYTE* dir, /* Pointer to the key entry */ + DWORD cl /* Value to be set */ +) +{ + st_word(dir + DIR_FstClusLO, (WORD)cl); + if (fs->fs_type == FS_FAT32) { + st_word(dir + DIR_FstClusHI, (WORD)(cl >> 16)); + } +} +#endif + + + +#if _USE_LFN != 0 +/*------------------------------------------------------------------------*/ +/* FAT-LFN: LFN handling */ +/*------------------------------------------------------------------------*/ +static +const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN characters in the directory entry */ + + +/*--------------------------------------------------------*/ +/* FAT-LFN: Compare a part of file name with an LFN entry */ +/*--------------------------------------------------------*/ +static +int cmp_lfn ( /* 1:matched, 0:not matched */ + const WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */ + BYTE* dir /* Pointer to the directory entry containing the part of LFN */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + + i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + + for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ + uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ + if (wc) { + if (i >= _MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) { /* Compare it */ + return 0; /* Not matched */ + } + wc = uc; + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } + + if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) return 0; /* Last segment matched but different length */ + + return 1; /* The part of LFN matched */ +} + + +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT +/*-----------------------------------------------------*/ +/* FAT-LFN: Pick a part of file name from an LFN entry */ +/*-----------------------------------------------------*/ +static +int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ + WCHAR* lfnbuf, /* Pointer to the LFN working buffer */ + BYTE* dir /* Pointer to the LFN entry */ +) +{ + UINT i, s; + WCHAR wc, uc; + + + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ + + i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ + + for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ + uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ + if (wc) { + if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + lfnbuf[i++] = wc = uc; /* Store it */ + } else { + if (uc != 0xFFFF) return 0; /* Check filler */ + } + } + + if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ + if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ + lfnbuf[i] = 0; + } + + return 1; /* The part of LFN is valid */ +} +#endif + + +#if !_FS_READONLY +/*-----------------------------------------*/ +/* FAT-LFN: Create an entry of LFN entries */ +/*-----------------------------------------*/ +static +void put_lfn ( + const WCHAR* lfn, /* Pointer to the LFN */ + BYTE* dir, /* Pointer to the LFN entry to be created */ + BYTE ord, /* LFN order (1-20) */ + BYTE sum /* Checksum of the corresponding SFN */ +) +{ + UINT i, s; + WCHAR wc; + + + dir[LDIR_Chksum] = sum; /* Set checksum */ + dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ + dir[LDIR_Type] = 0; + st_word(dir + LDIR_FstClusLO, 0); + + i = (ord - 1) * 13; /* Get offset in the LFN working buffer */ + s = wc = 0; + do { + if (wc != 0xFFFF) wc = lfn[i++]; /* Get an effective character */ + st_word(dir + LfnOfs[s], wc); /* Put it */ + if (wc == 0) wc = 0xFFFF; /* Padding characters for left locations */ + } while (++s < 13); + if (wc == 0xFFFF || !lfn[i]) ord |= LLEF; /* Last LFN part is the start of LFN sequence */ + dir[LDIR_Ord] = ord; /* Set the LFN order */ +} + +#endif /* !_FS_READONLY */ +#endif /* _USE_LFN != 0 */ + + + +#if _USE_LFN != 0 && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* FAT-LFN: Create a Numbered SFN */ +/*-----------------------------------------------------------------------*/ + +static +void gen_numname ( + BYTE* dst, /* Pointer to the buffer to store numbered SFN */ + const BYTE* src, /* Pointer to SFN */ + const WCHAR* lfn, /* Pointer to LFN */ + UINT seq /* Sequence number */ +) +{ + BYTE ns[8], c; + UINT i, j; + WCHAR wc; + DWORD sr; + + + mem_cpy(dst, src, 11); + + if (seq > 5) { /* In case of many collisions, generate a hash number instead of sequential number */ + sr = seq; + while (*lfn) { /* Create a CRC */ + wc = *lfn++; + for (i = 0; i < 16; i++) { + sr = (sr << 1) + (wc & 1); + wc >>= 1; + if (sr & 0x10000) sr ^= 0x11021; + } + } + seq = (UINT)sr; + } + + /* itoa (hexdecimal) */ + i = 7; + do { + c = (BYTE)((seq % 16) + '0'); + if (c > '9') c += 7; + ns[i--] = c; + seq /= 16; + } while (seq); + ns[i] = '~'; + + /* Append the number */ + for (j = 0; j < i && dst[j] != ' '; j++) { + if (IsDBCS1(dst[j])) { + if (j == i - 1) break; + j++; + } + } + do { + dst[j++] = (i < 8) ? ns[i++] : ' '; + } while (j < 8); +} +#endif /* _USE_LFN != 0 && !_FS_READONLY */ + + + +#if _USE_LFN != 0 +/*-----------------------------------------------------------------------*/ +/* FAT-LFN: Calculate checksum of an SFN entry */ +/*-----------------------------------------------------------------------*/ + +static +BYTE sum_sfn ( + const BYTE* dir /* Pointer to the SFN entry */ +) +{ + BYTE sum = 0; + UINT n = 11; + + do { + sum = (sum >> 1) + (sum << 7) + *dir++; + } while (--n); + return sum; +} + +#endif /* _USE_LFN != 0 */ + + + +#if _FS_EXFAT +/*-----------------------------------------------------------------------*/ +/* exFAT: Checksum */ +/*-----------------------------------------------------------------------*/ + +static +WORD xdir_sum ( /* Get checksum of the directoly block */ + const BYTE* dir /* Directory entry block to be calculated */ +) +{ + UINT i, szblk; + WORD sum; + + + szblk = (dir[XDIR_NumSec] + 1) * SZDIRE; + for (i = sum = 0; i < szblk; i++) { + if (i == XDIR_SetSum) { /* Skip sum field */ + i++; + } else { + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + dir[i]; + } + } + return sum; +} + + + +static +WORD xname_sum ( /* Get check sum (to be used as hash) of the name */ + const WCHAR* name /* File name to be calculated */ +) +{ + WCHAR chr; + WORD sum = 0; + + + while ((chr = *name++) != 0) { + chr = ff_wtoupper(chr); /* File name needs to be ignored case */ + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr & 0xFF); + sum = ((sum & 1) ? 0x8000 : 0) + (sum >> 1) + (chr >> 8); + } + return sum; +} + + +#if !_FS_READONLY && _USE_MKFS +static +DWORD xsum32 ( + BYTE dat, /* Data to be sumed */ + DWORD sum /* Previous value */ +) +{ + sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat; + return sum; +} +#endif + + +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 +/*------------------------------------------------------*/ +/* exFAT: Get object information from a directory block */ +/*------------------------------------------------------*/ + +static +void get_xdir_info ( + BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */ + FILINFO* fno /* Buffer to store the extracted file information */ +) +{ + UINT di, si; + WCHAR w; +#if !_LFN_UNICODE + UINT nc; +#endif + + /* Get file name */ + di = 0; +#if _LFN_UNICODE + for (si = SZDIRE * 2; di < dirb[XDIR_NumName]; si += 2, di++) { + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + w = ld_word(dirb + si); /* Get a character */ + if (di >= _MAX_LFN) { di = 0; break; } /* Buffer overflow --> inaccessible object name */ + fno->fname[di] = w; /* Store it */ + } +#else + for (si = SZDIRE * 2, nc = 0; nc < dirb[XDIR_NumName]; si += 2, nc++) { + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + w = ff_convert(ld_word(dirb + si), 0); /* Get a character and Unicode -> OEM */ + if (_DF1S && w >= 0x100) { /* Is it a double byte char? (always false at SBCS cfg) */ + fno->fname[di++] = (char)(w >> 8); /* Put 1st byte of the DBC */ + } + if (w == 0 || di >= _MAX_LFN) { di = 0; break; } /* Invalid char or buffer overflow --> inaccessible object name */ + fno->fname[di++] = (char)w; + } +#endif + if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ + fno->fname[di] = 0; /* Terminate file name */ + + fno->altname[0] = 0; /* No SFN */ + fno->fattrib = dirb[XDIR_Attr]; /* Attribute */ + fno->fsize = (fno->fattrib & AM_DIR) ? 0 : ld_qword(dirb + XDIR_FileSize); /* Size */ + fno->ftime = ld_word(dirb + XDIR_ModTime + 0); /* Time */ + fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */ +} + +#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ + + +/*-----------------------------------*/ +/* exFAT: Get a directry entry block */ +/*-----------------------------------*/ + +static +FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ + DIR* dp /* Pointer to the reading direcotry object pointing the 85 entry */ +) +{ + FRESULT res; + UINT i, sz_ent; + BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ + + + /* Load 85 entry */ + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; + mem_cpy(dirb + 0, dp->dir, SZDIRE); + sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; + if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; + + /* Load C0 entry */ + res = dir_next(dp, 0); + if (res != FR_OK) return res; + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; + mem_cpy(dirb + SZDIRE, dp->dir, SZDIRE); + if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; + + /* Load C1 entries */ + i = SZDIRE * 2; /* C1 offset */ + do { + res = dir_next(dp, 0); + if (res != FR_OK) return res; + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) return res; + if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; + if (i < MAXDIRB(_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); + } while ((i += SZDIRE) < sz_ent); + + /* Sanity check (do it when accessible object name) */ + if (i <= MAXDIRB(_MAX_LFN)) { + if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + } + return FR_OK; +} + + +#if !_FS_READONLY || _FS_RPATH != 0 +/*------------------------------------------------*/ +/* exFAT: Load the object's directory entry block */ +/*------------------------------------------------*/ +static +FRESULT load_obj_dir ( + DIR* dp, /* Blank directory object to be used to access containing direcotry */ + const _FDID* obj /* Object with its containing directory information */ +) +{ + FRESULT res; + + /* Open object containing directory */ + dp->obj.fs = obj->fs; + dp->obj.sclust = obj->c_scl; + dp->obj.stat = (BYTE)obj->c_size; + dp->obj.objsize = obj->c_size & 0xFFFFFF00; + dp->blk_ofs = obj->c_ofs; + + res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ + if (res == FR_OK) { + res = load_xdir(dp); /* Load the object's entry block */ + } + return res; +} +#endif + + +#if !_FS_READONLY +/*-----------------------------------------------*/ +/* exFAT: Store the directory block to the media */ +/*-----------------------------------------------*/ +static +FRESULT store_xdir ( + DIR* dp /* Pointer to the direcotry object */ +) +{ + FRESULT res; + UINT nent; + BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ + + /* Create set sum */ + st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); + nent = dirb[XDIR_NumSec] + 1; + + /* Store the set of directory to the volume */ + res = dir_sdi(dp, dp->blk_ofs); + while (res == FR_OK) { + res = move_window(dp->obj.fs, dp->sect); + if (res != FR_OK) break; + mem_cpy(dp->dir, dirb, SZDIRE); + dp->obj.fs->wflag = 1; + if (--nent == 0) break; + dirb += SZDIRE; + res = dir_next(dp, 0); + } + return (res == FR_OK || res == FR_DISK_ERR) ? res : FR_INT_ERR; +} + + + +/*-------------------------------------------*/ +/* exFAT: Create a new directory enrty block */ +/*-------------------------------------------*/ + +static +void create_xdir ( + BYTE* dirb, /* Pointer to the direcotry entry block buffer */ + const WCHAR* lfn /* Pointer to the nul terminated file name */ +) +{ + UINT i; + BYTE nb, nc; + WCHAR chr; + + + /* Create 85+C0 entry */ + mem_set(dirb, 0, 2 * SZDIRE); + dirb[XDIR_Type] = 0x85; + dirb[XDIR_Type + SZDIRE] = 0xC0; + + /* Create C1 entries */ + nc = 0; nb = 1; chr = 1; i = SZDIRE * 2; + do { + dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ + do { /* Fill name field */ + if (chr && (chr = lfn[nc]) != 0) nc++; /* Get a character if exist */ + st_word(dirb + i, chr); /* Store it */ + } while ((i += 2) % SZDIRE != 0); + nb++; + } while (lfn[nc]); /* Fill next entry if any char follows */ + + dirb[XDIR_NumName] = nc; /* Set name length */ + dirb[XDIR_NumSec] = nb; /* Set block length */ + st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ +} + +#endif /* !_FS_READONLY */ +#endif /* _FS_EXFAT */ + + + +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT +/*-----------------------------------------------------------------------*/ +/* Read an object from the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_read ( + DIR* dp, /* Pointer to the directory object */ + int vol /* Filtered by 0:file/directory or 1:volume label */ +) +{ + FRESULT res = FR_NO_FILE; + FATFS *fs = dp->obj.fs; + BYTE a, c; +#if _USE_LFN != 0 + BYTE ord = 0xFF, sum = 0xFF; +#endif + + while (dp->sect) { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + c = dp->dir[DIR_Name]; /* Test for the entry type */ + if (c == 0) { + res = FR_NO_FILE; break; /* Reached to end of the directory */ + } +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + if (_USE_LABEL && vol) { + if (c == 0x83) break; /* Volume label entry? */ + } else { + if (c == 0x85) { /* Start of the file entry block? */ + dp->blk_ofs = dp->dptr; /* Get location of the block */ + res = load_xdir(dp); /* Load the entry block */ + if (res == FR_OK) { + dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */ + } + break; + } + } + } else +#endif + { /* On the FAT12/16/32 volume */ + dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */ +#if _USE_LFN != 0 /* LFN configuration */ + if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */ + ord = 0xFF; + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (c & LLEF) { /* Is it start of an LFN sequence? */ + sum = dp->dir[LDIR_Chksum]; + c &= (BYTE)~LLEF; ord = c; + dp->blk_ofs = dp->dptr; + } + /* Check LFN validity and capture it */ + ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + } else { /* An SFN entry is found */ + if (ord || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */ + dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */ + } + break; + } + } +#else /* Non LFN configuration */ + if (c != DDEM && c != '.' && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) { /* Is it a valid entry? */ + break; + } +#endif + } + res = dir_next(dp, 0); /* Next entry */ + if (res != FR_OK) break; + } + + if (res != FR_OK) dp->sect = 0; /* Terminate the read operation on error or EOT */ + return res; +} + +#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */ + + + +/*-----------------------------------------------------------------------*/ +/* Directory handling - Find an object in the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ + DIR* dp /* Pointer to the directory object with the file name */ +) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; + BYTE c; +#if _USE_LFN != 0 + BYTE a, ord, sum; +#endif + + res = dir_sdi(dp, 0); /* Rewind directory object */ + if (res != FR_OK) return res; +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + BYTE nc; + UINT di, ni; + WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ + + while ((res = dir_read(dp, 0)) == FR_OK) { /* Read an item */ +#if _MAX_LFN < 255 + if (fs->dirbuf[XDIR_NumName] > _MAX_LFN) continue; /* Skip comparison if inaccessible object name */ +#endif + if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ + for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ + if ((di % SZDIRE) == 0) di += 2; + if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; + } + if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */ + } + return res; + } +#endif + /* On the FAT12/16/32 volume */ +#if _USE_LFN != 0 + ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ +#endif + do { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + c = dp->dir[DIR_Name]; + if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of table */ +#if _USE_LFN != 0 /* LFN configuration */ + dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; + if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ + } else { + if (a == AM_LFN) { /* An LFN entry is found */ + if (!(dp->fn[NSFLAG] & NS_NOLFN)) { + if (c & LLEF) { /* Is it start of LFN sequence? */ + sum = dp->dir[LDIR_Chksum]; + c &= (BYTE)~LLEF; ord = c; /* LFN start order */ + dp->blk_ofs = dp->dptr; /* Start offset of LFN */ + } + /* Check validity of the LFN entry and compare it with given name */ + ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF; + } + } else { /* An SFN entry is found */ + if (!ord && sum == sum_sfn(dp->dir)) break; /* LFN matched? */ + if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* SFN matched? */ + ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */ + } + } +#else /* Non LFN configuration */ + dp->obj.attr = dp->dir[DIR_Attr] & AM_MASK; + if (!(dp->dir[DIR_Attr] & AM_VOL) && !mem_cmp(dp->dir, dp->fn, 11)) break; /* Is it a valid entry? */ +#endif + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); + + return res; +} + + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Register an object to the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many SFN collision, FR_DISK_ERR:disk error */ + DIR* dp /* Target directory with object name to be created */ +) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; +#if _USE_LFN != 0 /* LFN configuration */ + UINT n, nlen, nent; + BYTE sn[12], sum; + + + if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ + for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + DIR dj; + + nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ + res = dir_alloc(dp, nent); /* Allocate entries */ + if (res != FR_OK) return res; + dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ + + if (dp->obj.sclust != 0 && (dp->obj.stat & 4)) { /* Has the sub-directory been stretched? */ + dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ + res = fill_first_frag(&dp->obj); /* Fill first fragment on the FAT if needed */ + if (res != FR_OK) return res; + res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + if (res != FR_OK) return res; + res = load_obj_dir(&dj, &dp->obj); /* Load the object status */ + if (res != FR_OK) return res; + st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ + st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); + fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; + res = store_xdir(&dj); /* Store the object status */ + if (res != FR_OK) return res; + } + + create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */ + return FR_OK; + } +#endif + /* On the FAT12/16/32 volume */ + mem_cpy(sn, dp->fn, 12); + if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */ + dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */ + for (n = 1; n < 100; n++) { + gen_numname(dp->fn, sn, fs->lfnbuf, n); /* Generate a numbered name */ + res = dir_find(dp); /* Check if the name collides with existing SFN */ + if (res != FR_OK) break; + } + if (n == 100) return FR_DENIED; /* Abort if too many collisions */ + if (res != FR_NO_FILE) return res; /* Abort if the result is other than 'not collided' */ + dp->fn[NSFLAG] = sn[NSFLAG]; + } + + /* Create an SFN with/without LFNs. */ + nent = (sn[NSFLAG] & NS_LFN) ? (nlen + 12) / 13 + 1 : 1; /* Number of entries to allocate */ + res = dir_alloc(dp, nent); /* Allocate entries */ + if (res == FR_OK && --nent) { /* Set LFN entry if needed */ + res = dir_sdi(dp, dp->dptr - nent * SZDIRE); + if (res == FR_OK) { + sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */ + do { /* Store LFN entries in bottom first */ + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum); + fs->wflag = 1; + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK && --nent); + } + } + +#else /* Non LFN configuration */ + res = dir_alloc(dp, 1); /* Allocate an entry for SFN */ + +#endif + + /* Set SFN entry */ + if (res == FR_OK) { + res = move_window(fs, dp->sect); + if (res == FR_OK) { + mem_set(dp->dir, 0, SZDIRE); /* Clean the entry */ + mem_cpy(dp->dir + DIR_Name, dp->fn, 11); /* Put SFN */ +#if _USE_LFN != 0 + dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */ +#endif + fs->wflag = 1; + } + } + + return res; +} + +#endif /* !_FS_READONLY */ + + + +#if !_FS_READONLY && _FS_MINIMIZE == 0 +/*-----------------------------------------------------------------------*/ +/* Remove an object from the directory */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */ + DIR* dp /* Directory object pointing the entry to be removed */ +) +{ + FRESULT res; + FATFS *fs = dp->obj.fs; +#if _USE_LFN != 0 /* LFN configuration */ + DWORD last = dp->dptr; + + res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */ + if (res == FR_OK) { + do { + res = move_window(fs, dp->sect); + if (res != FR_OK) break; + /* Mark an entry 'deleted' */ + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + dp->dir[XDIR_Type] &= 0x7F; + } else { /* On the FAT12/16/32 volume */ + dp->dir[DIR_Name] = DDEM; + } + fs->wflag = 1; + if (dp->dptr >= last) break; /* If reached last entry then all entries of the object has been deleted. */ + res = dir_next(dp, 0); /* Next entry */ + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR; + } +#else /* Non LFN configuration */ + + res = move_window(fs, dp->sect); + if (res == FR_OK) { + dp->dir[DIR_Name] = DDEM; + fs->wflag = 1; + } +#endif + + return res; +} + +#endif /* !_FS_READONLY && _FS_MINIMIZE == 0 */ + + + +#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 +/*-----------------------------------------------------------------------*/ +/* Get file information from directory entry */ +/*-----------------------------------------------------------------------*/ + +static +void get_fileinfo ( /* No return code */ + DIR* dp, /* Pointer to the directory object */ + FILINFO* fno /* Pointer to the file information to be filled */ +) +{ + UINT i, j; + TCHAR c; + DWORD tm; +#if _USE_LFN != 0 + WCHAR w, lfv; + FATFS *fs = dp->obj.fs; +#endif + + + fno->fname[0] = 0; /* Invaidate file info */ + if (!dp->sect) return; /* Exit if read pointer has reached end of directory */ + +#if _USE_LFN != 0 /* LFN configuration */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + get_xdir_info(fs->dirbuf, fno); + return; + } else +#endif + { /* On the FAT12/16/32 volume */ + if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */ + i = j = 0; + while ((w = fs->lfnbuf[j++]) != 0) { /* Get an LFN character */ +#if !_LFN_UNICODE + w = ff_convert(w, 0); /* Unicode -> OEM */ + if (w == 0) { i = 0; break; } /* No LFN if it could not be converted */ + if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */ + fno->fname[i++] = (char)(w >> 8); + } +#endif + if (i >= _MAX_LFN) { i = 0; break; } /* No LFN if buffer overflow */ + fno->fname[i++] = (TCHAR)w; + } + fno->fname[i] = 0; /* Terminate the LFN */ + } + } + + i = j = 0; + lfv = fno->fname[i]; /* LFN is exist if non-zero */ + while (i < 11) { /* Copy name body and extension */ + c = (TCHAR)dp->dir[i++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ + if (i == 9) { /* Insert a . if extension is exist */ + if (!lfv) fno->fname[j] = '.'; + fno->altname[j++] = '.'; + } +#if _LFN_UNICODE + if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dp->dir[i])) { + c = c << 8 | dp->dir[i++]; + } + c = ff_convert(c, 1); /* OEM -> Unicode */ + if (!c) c = '?'; +#endif + fno->altname[j] = c; + if (!lfv) { + if (IsUpper(c) && (dp->dir[DIR_NTres] & ((i >= 9) ? NS_EXT : NS_BODY))) { + c += 0x20; /* To lower */ + } + fno->fname[j] = c; + } + j++; + } + if (!lfv) { + fno->fname[j] = 0; + if (!dp->dir[DIR_NTres]) j = 0; /* Altname is no longer needed if neither LFN nor case info is exist. */ + } + fno->altname[j] = 0; /* Terminate the SFN */ + +#else /* Non-LFN configuration */ + i = j = 0; + while (i < 11) { /* Copy name body and extension */ + c = (TCHAR)dp->dir[i++]; + if (c == ' ') continue; /* Skip padding spaces */ + if (c == RDDEM) c = (TCHAR)DDEM; /* Restore replaced DDEM character */ + if (i == 9) fno->fname[j++] = '.'; /* Insert a . if extension is exist */ + fno->fname[j++] = c; + } + fno->fname[j] = 0; +#endif + + fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */ + fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */ + tm = ld_dword(dp->dir + DIR_ModTime); /* Timestamp */ + fno->ftime = (WORD)tm; fno->fdate = (WORD)(tm >> 16); +} + +#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */ + + + +#if _USE_FIND && _FS_MINIMIZE <= 1 +/*-----------------------------------------------------------------------*/ +/* Pattern matching */ +/*-----------------------------------------------------------------------*/ + +static +WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */ + const TCHAR** ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */ +) +{ +#if !_LFN_UNICODE + WCHAR chr; + + chr = (BYTE)*(*ptr)++; /* Get a byte */ + if (IsLower(chr)) chr -= 0x20; /* To upper ASCII char */ +#ifdef _EXCVT + if (chr >= 0x80) chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */ +#else + if (IsDBCS1(chr) && IsDBCS2(**ptr)) { /* Get DBC 2nd byte if needed */ + chr = chr << 8 | (BYTE)*(*ptr)++; + } +#endif + return chr; +#else + return ff_wtoupper(*(*ptr)++); /* Get a word and to upper */ +#endif +} + + +static +int pattern_matching ( /* 0:not matched, 1:matched */ + const TCHAR* pat, /* Matching pattern */ + const TCHAR* nam, /* String to be tested */ + int skip, /* Number of pre-skip chars (number of ?s) */ + int inf /* Infinite search (* specified) */ +) +{ + const TCHAR *pp, *np; + WCHAR pc, nc; + int nm, nx; + + + while (skip--) { /* Pre-skip name chars */ + if (!get_achar(&nam)) return 0; /* Branch mismatched if less name chars */ + } + if (!*pat && inf) return 1; /* (short circuit) */ + + do { + pp = pat; np = nam; /* Top of pattern and name to match */ + for (;;) { + if (*pp == '?' || *pp == '*') { /* Wildcard? */ + nm = nx = 0; + do { /* Analyze the wildcard chars */ + if (*pp++ == '?') nm++; else nx = 1; + } while (*pp == '?' || *pp == '*'); + if (pattern_matching(pp, np, nm, nx)) return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */ + nc = *np; break; /* Branch mismatched */ + } + pc = get_achar(&pp); /* Get a pattern char */ + nc = get_achar(&np); /* Get a name char */ + if (pc != nc) break; /* Branch mismatched? */ + if (pc == 0) return 1; /* Branch matched? (matched at end of both strings) */ + } + get_achar(&nam); /* nam++ */ + } while (inf && nc); /* Retry until end of name if infinite search is specified */ + + return 0; +} + +#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */ + + + +/*-----------------------------------------------------------------------*/ +/* Pick a top segment and create the object name in directory form */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */ + DIR* dp, /* Pointer to the directory object */ + const TCHAR** path /* Pointer to pointer to the segment in the path string */ +) +{ +#if _USE_LFN != 0 /* LFN configuration */ + BYTE b, cf; + WCHAR w, *lfn; + UINT i, ni, si, di; + const TCHAR *p; + + /* Create LFN in Unicode */ + p = *path; lfn = dp->obj.fs->lfnbuf; si = di = 0; + for (;;) { + w = p[si++]; /* Get a character */ + if (w < ' ') break; /* Break if end of the path name */ + if (w == '/' || w == '\\') { /* Break if a separator is found */ + while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ + break; + } + if (di >= _MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */ +#if !_LFN_UNICODE + w &= 0xFF; + if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ + b = (BYTE)p[si++]; /* Get 2nd byte */ + w = (w << 8) + b; /* Create a DBC */ + if (!IsDBCS2(b)) return FR_INVALID_NAME; /* Reject invalid sequence */ + } + w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */ + if (!w) return FR_INVALID_NAME; /* Reject invalid code */ +#endif + if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) return FR_INVALID_NAME; /* Reject illegal characters for LFN */ + lfn[di++] = w; /* Store the Unicode character */ + } + *path = &p[si]; /* Return pointer to the next segment */ + cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ +#if _FS_RPATH != 0 + if ((di == 1 && lfn[di - 1] == '.') || + (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */ + lfn[di] = 0; + for (i = 0; i < 11; i++) /* Create dot name for SFN entry */ + dp->fn[i] = (i < di) ? '.' : ' '; + dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ + return FR_OK; + } +#endif + while (di) { /* Snip off trailing spaces and dots if exist */ + w = lfn[di - 1]; + if (w != ' ' && w != '.') break; + di--; + } + lfn[di] = 0; /* LFN is created */ + if (di == 0) return FR_INVALID_NAME; /* Reject nul name */ + + /* Create SFN in directory form */ + mem_set(dp->fn, ' ', 11); + for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */ + if (si) cf |= NS_LOSS | NS_LFN; + while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */ + + i = b = 0; ni = 8; + for (;;) { + w = lfn[si++]; /* Get an LFN character */ + if (!w) break; /* Break on end of the LFN */ + if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */ + cf |= NS_LOSS | NS_LFN; continue; + } + + if (i >= ni || si == di) { /* Extension or end of SFN */ + if (ni == 11) { /* Long extension */ + cf |= NS_LOSS | NS_LFN; break; + } + if (si != di) cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */ + if (si > di) break; /* No extension */ + si = di; i = 8; ni = 11; /* Enter extension section */ + b <<= 2; continue; + } + + if (w >= 0x80) { /* Non ASCII character */ +#ifdef _EXCVT + w = ff_convert(w, 0); /* Unicode -> OEM code */ + if (w) w = ExCvt[w - 0x80]; /* Convert extended character to upper (SBCS) */ +#else + w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */ +#endif + cf |= NS_LFN; /* Force create LFN entry */ + } + + if (_DF1S && w >= 0x100) { /* Is this DBC? (always false at SBCS cfg) */ + if (i >= ni - 1) { + cf |= NS_LOSS | NS_LFN; i = ni; continue; + } + dp->fn[i++] = (BYTE)(w >> 8); + } else { /* SBC */ + if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal characters for SFN */ + w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */ + } else { + if (IsUpper(w)) { /* ASCII large capital */ + b |= 2; + } else { + if (IsLower(w)) { /* ASCII small capital */ + b |= 1; w -= 0x20; + } + } + } + } + dp->fn[i++] = (BYTE)w; + } + + if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ + + if (ni == 8) b <<= 2; + if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) cf |= NS_LFN; /* Create LFN entry when there are composite capitals */ + if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */ + if ((b & 0x03) == 0x01) cf |= NS_EXT; /* NT flag (Extension has only small capital) */ + if ((b & 0x0C) == 0x04) cf |= NS_BODY; /* NT flag (Filename has only small capital) */ + } + + dp->fn[NSFLAG] = cf; /* SFN is created */ + + return FR_OK; + + +#else /* _USE_LFN != 0 : Non-LFN configuration */ + BYTE c, d, *sfn; + UINT ni, si, i; + const char *p; + + /* Create file name in directory form */ + p = *path; sfn = dp->fn; + mem_set(sfn, ' ', 11); + si = i = 0; ni = 8; +#if _FS_RPATH != 0 + if (p[si] == '.') { /* Is this a dot entry? */ + for (;;) { + c = (BYTE)p[si++]; + if (c != '.' || si >= 3) break; + sfn[i++] = c; + } + if (c != '/' && c != '\\' && c > ' ') return FR_INVALID_NAME; + *path = p + si; /* Return pointer to the next segment */ + sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of the path */ + return FR_OK; + } +#endif + for (;;) { + c = (BYTE)p[si++]; + if (c <= ' ') break; /* Break if end of the path name */ + if (c == '/' || c == '\\') { /* Break if a separator is found */ + while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */ + break; + } + if (c == '.' || i >= ni) { /* End of body or over size? */ + if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Over size or invalid dot */ + i = 8; ni = 11; /* Goto extension */ + continue; + } + if (c >= 0x80) { /* Extended character? */ +#ifdef _EXCVT + c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */ +#else +#if !_DF1S + return FR_INVALID_NAME; /* Reject extended characters (ASCII only cfg) */ +#endif +#endif + } + if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false at SBCS cfg.) */ + d = (BYTE)p[si++]; /* Get 2nd byte */ + if (!IsDBCS2(d) || i >= ni - 1) return FR_INVALID_NAME; /* Reject invalid DBC */ + sfn[i++] = c; + sfn[i++] = d; + } else { /* SBC */ + if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */ + if (IsLower(c)) c -= 0x20; /* To upper */ + sfn[i++] = c; + } + } + *path = p + si; /* Return pointer to the next segment */ + if (i == 0) return FR_INVALID_NAME; /* Reject nul string */ + + if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */ + sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */ + + return FR_OK; +#endif /* _USE_LFN != 0 */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Follow a file path */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ + DIR* dp, /* Directory object to return last directory and found object */ + const TCHAR* path /* Full-path string to find a file or directory */ +) +{ + FRESULT res; + BYTE ns; + _FDID *obj = &dp->obj; + FATFS *fs = obj->fs; + + +#if _FS_RPATH != 0 + if (*path != '/' && *path != '\\') { /* Without heading separator */ + obj->sclust = fs->cdir; /* Start from current directory */ + } else +#endif + { /* With heading separator */ + while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ + obj->sclust = 0; /* Start from root directory */ + } +#if _FS_EXFAT + obj->n_frag = 0; /* Invalidate last fragment counter of the object */ +#if _FS_RPATH != 0 + if (fs->fs_type == FS_EXFAT && obj->sclust) { /* Retrieve the sub-directory status if needed */ + DIR dj; + + obj->c_scl = fs->cdc_scl; + obj->c_size = fs->cdc_size; + obj->c_ofs = fs->cdc_ofs; + res = load_obj_dir(&dj, obj); + if (res != FR_OK) return res; + obj->objsize = ld_dword(fs->dirbuf + XDIR_FileSize); + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + } +#endif +#endif + + if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ + dp->fn[NSFLAG] = NS_NONAME; + res = dir_sdi(dp, 0); + + } else { /* Follow path */ + for (;;) { + res = create_name(dp, &path); /* Get a segment name of the path */ + if (res != FR_OK) break; + res = dir_find(dp); /* Find an object with the segment name */ + ns = dp->fn[NSFLAG]; + if (res != FR_OK) { /* Failed to find the object */ + if (res == FR_NO_FILE) { /* Object is not found */ + if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, stay there */ + if (!(ns & NS_LAST)) continue; /* Continue to follow if not last segment */ + dp->fn[NSFLAG] = NS_NONAME; + res = FR_OK; + } else { /* Could not find the object */ + if (!(ns & NS_LAST)) res = FR_NO_PATH; /* Adjust error code if not last segment */ + } + } + break; + } + if (ns & NS_LAST) break; /* Last segment matched. Function completed. */ + /* Get into the sub-directory */ + if (!(obj->attr & AM_DIR)) { /* It is not a sub-directory and cannot follow */ + res = FR_NO_PATH; break; + } +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ + obj->c_scl = obj->sclust; + obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; + obj->c_ofs = dp->blk_ofs; + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Open next directory */ + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + } else +#endif + { + obj->sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */ + } + } + } + + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Get logical drive number from path name */ +/*-----------------------------------------------------------------------*/ + +static +int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ + const TCHAR** path /* Pointer to pointer to the path name */ +) +{ + const TCHAR *tp, *tt; + UINT i; + int vol = -1; +#if _STR_VOLUME_ID /* Find string drive id */ + static const char* const volid[] = {_VOLUME_STRS}; + const char *sp; + char c; + TCHAR tc; +#endif + + + if (*path) { /* If the pointer is not a null */ + for (tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find ':' in the path */ + if (*tt == ':') { /* If a ':' is exist in the path name */ + tp = *path; + i = *tp++ - '0'; + if (i < 10 && tp == tt) { /* Is there a numeric drive id? */ + if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */ + vol = (int)i; + *path = ++tt; + } + } +#if _STR_VOLUME_ID + else { /* No numeric drive number, find string drive id */ + i = 0; tt++; + do { + sp = volid[i]; tp = *path; + do { /* Compare a string drive id with path name */ + c = *sp++; tc = *tp++; + if (IsLower(tc)) tc -= 0x20; + } while (c && (TCHAR)c == tc); + } while ((c || tp != tt) && ++i < _VOLUMES); /* Repeat for each id until pattern match */ + if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */ + vol = (int)i; + *path = tt; + } + } +#endif + return vol; + } +#if _FS_RPATH != 0 && _VOLUMES >= 2 + vol = CurrVol; /* Current drive */ +#else + vol = 0; /* Drive 0 */ +#endif + } + return vol; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Load a sector and check if it is an FAT boot sector */ +/*-----------------------------------------------------------------------*/ + +static +BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ + FATFS* fs, /* File system object */ + DWORD sect /* Sector# (lba) to load and check if it is an FAT-VBR or not */ +) +{ + fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ + if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ + + if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed here even if the sector size is >512) */ + + if (fs->win[BS_JmpBoot] == 0xE9 || (fs->win[BS_JmpBoot] == 0xEB && fs->win[BS_JmpBoot + 2] == 0x90)) { + if ((ld_dword(fs->win + BS_FilSysType) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */ + if (ld_dword(fs->win + BS_FilSysType32) == 0x33544146) return 0; /* Check "FAT3" string */ + } +#if _FS_EXFAT + if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1; +#endif + return 2; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Find logical drive and check if the volume is mounted */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ + const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ + FATFS** rfs, /* Pointer to pointer to the found file system object */ + BYTE mode /* !=0: Check write protection for write access */ +) +{ + BYTE fmt, *pt; + int vol; + DSTATUS stat; + DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4]; + WORD nrsv; + FATFS *fs; + UINT i; + + + /* Get logical drive number */ + *rfs = 0; + vol = get_ldnumber(path); + if (vol < 0) return FR_INVALID_DRIVE; + + /* Check if the file system object is valid or not */ + fs = FatFs[vol]; /* Get pointer to the file system object */ + if (!fs) return FR_NOT_ENABLED; /* Is the file system object available? */ + + ENTER_FF(fs); /* Lock the volume */ + *rfs = fs; /* Return pointer to the file system object */ + + mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */ + if (fs->fs_type) { /* If the volume has been mounted */ + stat = disk_status(fs->drv); + if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */ + if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check write protection if needed */ + return FR_WRITE_PROTECTED; + } + return FR_OK; /* The file system object is valid */ + } + } + + /* The file system object is not valid. */ + /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */ + + fs->fs_type = 0; /* Clear the file system object */ + fs->drv = LD2PD(vol); /* Bind the logical drive and a physical drive */ + stat = disk_initialize(fs->drv); /* Initialize the physical drive */ + if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ + return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ + } + if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ + return FR_WRITE_PROTECTED; + } +#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ + if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; + if (SS(fs) > _MAX_SS || SS(fs) < _MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; +#endif + + /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */ + bsect = 0; + fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ + if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ + for (i = 0; i < 4; i++) { /* Get partition offset */ + pt = fs->win + (MBR_Table + i * SZ_PTE); + br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0; + } + i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ + if (i) i--; + do { /* Find an FAT volume */ + bsect = br[i]; + fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ + } while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4); + } + if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ + if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ + + /* An FAT volume is found (bsect). Following code initializes the file system object */ + +#if _FS_EXFAT + if (fmt == 1) { + QWORD maxlba; + + for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */ + if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; + + if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT revision (Must be 1.0) */ + + if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ + return FR_NO_FILESYSTEM; + } + + maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ + if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ + + fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */ + + fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */ + if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */ + + fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */ + if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */ + + nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */ + if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */ + fs->n_fatent = nclst + 2; + + /* Boundaries and Limits */ + fs->volbase = bsect; + fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); + fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); + if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ + fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); + + /* Check if bitmap location is in assumption (at the first cluster) */ + if (move_window(fs, clust2sect(fs, fs->dirbase)) != FR_OK) return FR_DISK_ERR; + for (i = 0; i < SS(fs); i += SZDIRE) { + if (fs->win[i] == 0x81 && ld_dword(fs->win + i + 20) == 2) break; /* 81 entry with cluster #2? */ + } + if (i == SS(fs)) return FR_NO_FILESYSTEM; +#if !_FS_READONLY + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ +#endif + fmt = FS_EXFAT; /* FAT sub-type */ + } else +#endif /* _FS_EXFAT */ + { + if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ + + fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); + fs->fsize = fasize; + + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ + if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ + fasize *= fs->n_fats; /* Number of sectors for FAT area */ + + fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ + if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ + + fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ + if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ + + tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); + + nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + + /* Determine the FAT sub type */ + sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + fmt = FS_FAT32; + if (nclst <= MAX_FAT16) fmt = FS_FAT16; + if (nclst <= MAX_FAT12) fmt = FS_FAT12; + + /* Boundaries and Limits */ + fs->n_fatent = nclst + 2; /* Number of FAT entries */ + fs->volbase = bsect; /* Volume start sector */ + fs->fatbase = bsect + nrsv; /* FAT start sector */ + fs->database = bsect + sysect; /* Data start sector */ + if (fmt == FS_FAT32) { + if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ + if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ + szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ + } else { + if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM;/* (BPB_RootEntCnt must not be 0) */ + fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ + szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ + fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); + } + if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ + +#if !_FS_READONLY + /* Get FSINFO if available */ + fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */ + fs->fsi_flag = 0x80; +#if (_FS_NOFSINFO & 3) != 3 + if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo32 == 1 */ + && ld_word(fs->win + BPB_FSInfo32) == 1 + && move_window(fs, bsect + 1) == FR_OK) + { + fs->fsi_flag = 0; + if (ld_word(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */ + && ld_dword(fs->win + FSI_LeadSig) == 0x41615252 + && ld_dword(fs->win + FSI_StrucSig) == 0x61417272) + { +#if (_FS_NOFSINFO & 1) == 0 + fs->free_clst = ld_dword(fs->win + FSI_Free_Count); +#endif +#if (_FS_NOFSINFO & 2) == 0 + fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free); +#endif + } + } +#endif /* (_FS_NOFSINFO & 3) != 3 */ +#endif /* !_FS_READONLY */ + } + + fs->fs_type = fmt; /* FAT sub-type */ + fs->id = ++Fsid; /* File system mount ID */ +#if _USE_LFN == 1 + fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ +#if _FS_EXFAT + fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ +#endif +#endif +#if _FS_RPATH != 0 + fs->cdir = 0; /* Initialize current directory */ +#endif +#if _FS_LOCK != 0 /* Clear file lock semaphores */ + clear_lock(fs); +#endif + return FR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Check if the file/directory object is valid or not */ +/*-----------------------------------------------------------------------*/ + +static +FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ + _FDID* obj, /* Pointer to the _OBJ, the 1st member in the FIL/DIR object, to check validity */ + FATFS** fs /* Pointer to pointer to the owner file system object to return */ +) +{ + FRESULT res = FR_INVALID_OBJECT; + + + if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ +#if _FS_REENTRANT + if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ + if (!(disk_status(obj->fs->drv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + res = FR_OK; + } else { + unlock_fs(obj->fs, FR_OK); + } + } else { + res = FR_TIMEOUT; + } +#else + if (!(disk_status(obj->fs->drv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + res = FR_OK; + } +#endif + } + *fs = (res == FR_OK) ? obj->fs : 0; /* Corresponding filesystem object */ + return res; +} + + + + +/*--------------------------------------------------------------------------- + + Public Functions (FatFs API) + +----------------------------------------------------------------------------*/ + + + +/*-----------------------------------------------------------------------*/ +/* Mount/Unmount a Logical Drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mount ( + FATFS* fs, /* Pointer to the file system object (NULL:unmount)*/ + const TCHAR* path, /* Logical drive number to be mounted/unmounted */ + BYTE opt /* Mode option 0:Do not mount (delayed mount), 1:Mount immediately */ +) +{ + FATFS *cfs; + int vol; + FRESULT res; + const TCHAR *rp = path; + + + /* Get logical drive number */ + vol = get_ldnumber(&rp); + if (vol < 0) return FR_INVALID_DRIVE; + cfs = FatFs[vol]; /* Pointer to fs object */ + + if (cfs) { +#if _FS_LOCK != 0 + clear_lock(cfs); +#endif +#if _FS_REENTRANT /* Discard sync object of the current volume */ + if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; +#endif + cfs->fs_type = 0; /* Clear old fs object */ + } + + if (fs) { + fs->fs_type = 0; /* Clear new fs object */ +#if _FS_REENTRANT /* Create sync object for the new volume */ + if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; +#endif + } + FatFs[vol] = fs; /* Register new fs object */ + + if (!fs || opt != 1) return FR_OK; /* Do not mount now, it will be mounted later */ + + res = find_volume(&path, &fs, 0); /* Force mounted the volume */ + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Open or Create a File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_open ( + FIL* fp, /* Pointer to the blank file object */ + const TCHAR* path, /* Pointer to the file name */ + BYTE mode /* Access mode and file open mode flags */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; +#if !_FS_READONLY + DWORD dw, cl, bcs, clst, sc; + FSIZE_t ofs; +#endif + DEF_NAMBUF + + + if (!fp) return FR_INVALID_OBJECT; + + /* Get logical drive */ + mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND | FA_SEEKEND; + res = find_volume(&path, &fs, mode); + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ +#if !_FS_READONLY /* R/W configuration */ + if (res == FR_OK) { + if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ + res = FR_INVALID_NAME; + } +#if _FS_LOCK != 0 + else { + res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + } +#endif + } + /* Create or Open a file */ + if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { + if (res != FR_OK) { /* No file, create new */ + if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ +#if _FS_LOCK != 0 + res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; +#else + res = dir_register(&dj); +#endif + } + mode |= FA_CREATE_ALWAYS; /* File is created */ + } + else { /* Any object is already existing */ + if (dj.obj.attr & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */ + res = FR_DENIED; + } else { + if (mode & FA_CREATE_NEW) res = FR_EXIST; /* Cannot create as new file */ + } + } + if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ + dw = GET_FATTIME(); +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + /* Get current allocation info */ + fp->obj.fs = fs; + fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); + fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + fp->obj.n_frag = 0; + /* Initialize directory entry block */ + st_dword(fs->dirbuf + XDIR_CrtTime, dw); /* Set created time */ + fs->dirbuf[XDIR_CrtTime10] = 0; + st_dword(fs->dirbuf + XDIR_ModTime, dw); /* Set modified time */ + fs->dirbuf[XDIR_ModTime10] = 0; + fs->dirbuf[XDIR_Attr] = AM_ARC; /* Reset attribute */ + st_dword(fs->dirbuf + XDIR_FstClus, 0); /* Reset file allocation info */ + st_qword(fs->dirbuf + XDIR_FileSize, 0); + st_qword(fs->dirbuf + XDIR_ValidFileSize, 0); + fs->dirbuf[XDIR_GenFlags] = 1; + res = store_xdir(&dj); + if (res == FR_OK && fp->obj.sclust) { /* Remove the cluster chain if exist */ + res = remove_chain(&fp->obj, fp->obj.sclust, 0); + fs->last_clst = fp->obj.sclust - 1; /* Reuse the cluster hole */ + } + } else +#endif + { + /* Clean directory info */ + st_dword(dj.dir + DIR_CrtTime, dw); /* Set created time */ + st_dword(dj.dir + DIR_ModTime, dw); /* Set modified time */ + dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */ + cl = ld_clust(fs, dj.dir); /* Get cluster chain */ + st_clust(fs, dj.dir, 0); /* Reset file allocation info */ + st_dword(dj.dir + DIR_FileSize, 0); + fs->wflag = 1; + + if (cl) { /* Remove the cluster chain if exist */ + dw = fs->winsect; + res = remove_chain(&dj.obj, cl, 0); + if (res == FR_OK) { + res = move_window(fs, dw); + fs->last_clst = cl - 1; /* Reuse the cluster hole */ + } + } + } + } + } + else { /* Open an existing file */ + if (res == FR_OK) { /* Following succeeded */ + if (dj.obj.attr & AM_DIR) { /* It is a directory */ + res = FR_NO_FILE; + } else { + if ((mode & FA_WRITE) && (dj.obj.attr & AM_RDO)) { /* R/O violation */ + res = FR_DENIED; + } + } + } + } + if (res == FR_OK) { + if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */ + mode |= FA_MODIFIED; + fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ + fp->dir_ptr = dj.dir; +#if _FS_LOCK != 0 + fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); + if (!fp->obj.lockid) res = FR_INT_ERR; +#endif + } +#else /* R/O configuration */ + if (res == FR_OK) { + if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ + res = FR_INVALID_NAME; + } else { + if (dj.obj.attr & AM_DIR) { /* It is a directory */ + res = FR_NO_FILE; + } + } + } +#endif + + if (res == FR_OK) { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ + fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; + fp->obj.c_ofs = dj.blk_ofs; + fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object allocation info */ + fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + } else +#endif + { + fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ + fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); + } +#if _USE_FASTSEEK + fp->cltbl = 0; /* Disable fast seek mode */ +#endif + fp->obj.fs = fs; /* Validate the file object */ + fp->obj.id = fs->id; + fp->flag = mode; /* Set file access mode */ + fp->err = 0; /* Clear error flag */ + fp->sect = 0; /* Invalidate current data sector */ + fp->fptr = 0; /* Set file pointer top of the file */ +#if !_FS_READONLY +#if !_FS_TINY + mem_set(fp->buf, 0, _MAX_SS); /* Clear sector buffer */ +#endif + if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */ + fp->fptr = fp->obj.objsize; /* Offset to seek */ + bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */ + clst = fp->obj.sclust; /* Follow the cluster chain */ + for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) { + clst = get_fat(&fp->obj, clst); + if (clst <= 1) res = FR_INT_ERR; + if (clst == 0xFFFFFFFF) res = FR_DISK_ERR; + } + fp->clust = clst; + if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */ + if ((sc = clust2sect(fs, clst)) == 0) { + res = FR_INT_ERR; + } else { + fp->sect = sc + (DWORD)(ofs / SS(fs)); +#if !_FS_TINY + if (disk_read(fs->drv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR; +#endif + } + } + } +#endif + } + + FREE_NAMBUF(); + } + + if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */ + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_read ( + FIL* fp, /* Pointer to the file object */ + void* buff, /* Pointer to data buffer */ + UINT btr, /* Number of bytes to read */ + UINT* br /* Pointer to number of bytes read */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst, sect; + FSIZE_t remain; + UINT rcnt, cc, csect; + BYTE *rbuff = (BYTE*)buff; + + + *br = 0; /* Clear read byte counter */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + remain = fp->obj.objsize - fp->fptr; + if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */ + + for ( ; btr; /* Repeat until all data read */ + rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ + if (csect == 0) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->obj.sclust; /* Follow cluster chain from the origin */ + } else { /* Middle or end of the file */ +#if _USE_FASTSEEK + if (fp->cltbl) { + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + } else +#endif + { + clst = get_fat(&fp->obj, fp->clust); /* Follow cluster chain on the FAT */ + } + } + if (clst < 2) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + sect = clust2sect(fs, fp->clust); /* Get current sector */ + if (!sect) ABORT(fs, FR_INT_ERR); + sect += csect; + cc = btr / SS(fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Read maximum contiguous sectors directly */ + if (csect + cc > fs->csize) { /* Clip at cluster boundary */ + cc = fs->csize - csect; + } + if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); +#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ +#if _FS_TINY + if (fs->wflag && fs->winsect - sect < cc) { + mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs)); + } +#else + if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) { + mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs)); + } +#endif +#endif + rcnt = SS(fs) * cc; /* Number of bytes transferred */ + continue; + } +#if !_FS_TINY + if (fp->sect != sect) { /* Load data sector if not in cache */ +#if !_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + } +#endif + fp->sect = sect; + } + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */ +#if _FS_TINY + if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ + mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ +#else + mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */ +#endif + } + + LEAVE_FF(fs, FR_OK); +} + + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Write File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_write ( + FIL* fp, /* Pointer to the file object */ + const void* buff, /* Pointer to the data to be written */ + UINT btw, /* Number of bytes to write */ + UINT* bw /* Pointer to number of bytes written */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst, sect; + UINT wcnt, cc, csect; + const BYTE *wbuff = (const BYTE*)buff; + + + *bw = 0; /* Clear write byte counter */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + /* Check fptr wrap-around (file size cannot reach 4GiB on FATxx) */ + if ((!_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) { + btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr); + } + + for ( ; btw; /* Repeat until all data written */ + wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize, *bw += wcnt, btw -= wcnt) { + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */ + if (csect == 0) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->obj.sclust; /* Follow from the origin */ + if (clst == 0) { /* If no cluster is allocated, */ + clst = create_chain(&fp->obj, 0); /* create a new cluster chain */ + } + } else { /* On the middle or end of the file */ +#if _USE_FASTSEEK + if (fp->cltbl) { + clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */ + } else +#endif + { + clst = create_chain(&fp->obj, fp->clust); /* Follow or stretch cluster chain on the FAT */ + } + } + if (clst == 0) break; /* Could not allocate a new cluster (disk full) */ + if (clst == 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */ + } +#if _FS_TINY + if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */ +#else + if (fp->flag & FA_DIRTY) { /* Write-back sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + sect = clust2sect(fs, fp->clust); /* Get current sector */ + if (!sect) ABORT(fs, FR_INT_ERR); + sect += csect; + cc = btw / SS(fs); /* When remaining bytes >= sector size, */ + if (cc) { /* Write maximum contiguous sectors directly */ + if (csect + cc > fs->csize) { /* Clip at cluster boundary */ + cc = fs->csize - csect; + } + if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR); +#if _FS_MINIMIZE <= 2 +#if _FS_TINY + if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs)); + fs->wflag = 0; + } +#else + if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */ + mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs)); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif +#endif + wcnt = SS(fs) * cc; /* Number of bytes transferred */ + continue; + } +#if _FS_TINY + if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */ + if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); + fs->winsect = sect; + } +#else + if (fp->sect != sect && /* Fill sector cache with file data */ + fp->fptr < fp->obj.objsize && + disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { + ABORT(fs, FR_DISK_ERR); + } +#endif + fp->sect = sect; + } + wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */ +#if _FS_TINY + if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */ + mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ + fs->wflag = 1; +#else + mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */ + fp->flag |= FA_DIRTY; +#endif + } + + fp->flag |= FA_MODIFIED; /* Set file change flag */ + + LEAVE_FF(fs, FR_OK); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Synchronize the File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_sync ( + FIL* fp /* Pointer to the file object */ +) +{ + FRESULT res; + FATFS *fs; + DWORD tm; + BYTE *dir; +#if _FS_EXFAT + DIR dj; + DEF_NAMBUF +#endif + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res == FR_OK) { + if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */ +#if !_FS_TINY + if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + /* Update the directory entry */ + tm = GET_FATTIME(); /* Modified time */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ + if (res == FR_OK) { + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } + if (res == FR_OK) { + INIT_NAMBUF(fs); + res = load_obj_dir(&dj, &fp->obj); /* Load directory entry block */ + if (res == FR_OK) { + fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive bit */ + fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation info */ + st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust); + st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize); + st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize); + st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */ + fs->dirbuf[XDIR_ModTime10] = 0; + st_dword(fs->dirbuf + XDIR_AccTime, 0); + res = store_xdir(&dj); /* Restore it to the directory */ + if (res == FR_OK) { + res = sync_fs(fs); + fp->flag &= (BYTE)~FA_MODIFIED; + } + } + FREE_NAMBUF(); + } + } else +#endif + { + res = move_window(fs, fp->dir_sect); + if (res == FR_OK) { + dir = fp->dir_ptr; + dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ + st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation info */ + st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */ + st_dword(dir + DIR_ModTime, tm); /* Update modified time */ + st_word(dir + DIR_LstAccDate, 0); + fs->wflag = 1; + res = sync_fs(fs); /* Restore it to the directory */ + fp->flag &= (BYTE)~FA_MODIFIED; + } + } + } + } + + LEAVE_FF(fs, res); +} + +#endif /* !_FS_READONLY */ + + + + +/*-----------------------------------------------------------------------*/ +/* Close File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_close ( + FIL* fp /* Pointer to the file object to be closed */ +) +{ + FRESULT res; + FATFS *fs; + +#if !_FS_READONLY + res = f_sync(fp); /* Flush cached data */ + if (res == FR_OK) +#endif + { + res = validate(&fp->obj, &fs); /* Lock volume */ + if (res == FR_OK) { +#if _FS_LOCK != 0 + res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ + if (res == FR_OK) +#endif + { + fp->obj.fs = 0; /* Invalidate file object */ + } +#if _FS_REENTRANT + unlock_fs(fs, FR_OK); /* Unlock volume */ +#endif + } + } + return res; +} + + + + +#if _FS_RPATH >= 1 +/*-----------------------------------------------------------------------*/ +/* Change Current Directory or Current Drive, Get Current Directory */ +/*-----------------------------------------------------------------------*/ + +#if _VOLUMES >= 2 +FRESULT f_chdrive ( + const TCHAR* path /* Drive number */ +) +{ + int vol; + + + /* Get logical drive number */ + vol = get_ldnumber(&path); + if (vol < 0) return FR_INVALID_DRIVE; + + CurrVol = (BYTE)vol; /* Set it as current volume */ + + return FR_OK; +} +#endif + + +FRESULT f_chdir ( + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + DEF_NAMBUF + + /* Get logical drive */ + res = find_volume(&path, &fs, 0); + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the path */ + if (res == FR_OK) { /* Follow completed */ + if (dj.fn[NSFLAG] & NS_NONAME) { + fs->cdir = dj.obj.sclust; /* It is the start directory itself */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->cdc_scl = dj.obj.c_scl; + fs->cdc_size = dj.obj.c_size; + fs->cdc_ofs = dj.obj.c_ofs; + } +#endif + } else { + if (dj.obj.attr & AM_DIR) { /* It is a sub-directory */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->cdir = ld_dword(fs->dirbuf + XDIR_FstClus); /* Sub-directory cluster */ + fs->cdc_scl = dj.obj.sclust; /* Save containing directory information */ + fs->cdc_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; + fs->cdc_ofs = dj.blk_ofs; + } else +#endif + { + fs->cdir = ld_clust(fs, dj.dir); /* Sub-directory cluster */ + } + } else { + res = FR_NO_PATH; /* Reached but a file */ + } + } + } + FREE_NAMBUF(); + if (res == FR_NO_FILE) res = FR_NO_PATH; + } + + LEAVE_FF(fs, res); +} + + +#if _FS_RPATH >= 2 +FRESULT f_getcwd ( + TCHAR* buff, /* Pointer to the directory path */ + UINT len /* Size of path */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + UINT i, n; + DWORD ccl; + TCHAR *tp; + FILINFO fno; + DEF_NAMBUF + + + *buff = 0; + /* Get logical drive */ + res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */ + if (res == FR_OK) { + dj.obj.fs = fs; + INIT_NAMBUF(fs); + i = len; /* Bottom of buffer (directory stack base) */ + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */ + dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */ + while ((ccl = dj.obj.sclust) != 0) { /* Repeat while current directory is a sub-directory */ + res = dir_sdi(&dj, 1 * SZDIRE); /* Get parent directory */ + if (res != FR_OK) break; + res = move_window(fs, dj.sect); + if (res != FR_OK) break; + dj.obj.sclust = ld_clust(fs, dj.dir); /* Goto parent directory */ + res = dir_sdi(&dj, 0); + if (res != FR_OK) break; + do { /* Find the entry links to the child directory */ + res = dir_read(&dj, 0); + if (res != FR_OK) break; + if (ccl == ld_clust(fs, dj.dir)) break; /* Found the entry */ + res = dir_next(&dj, 0); + } while (res == FR_OK); + if (res == FR_NO_FILE) res = FR_INT_ERR;/* It cannot be 'not found'. */ + if (res != FR_OK) break; + get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */ + for (n = 0; fno.fname[n]; n++) ; + if (i < n + 3) { + res = FR_NOT_ENOUGH_CORE; break; + } + while (n) buff[--i] = fno.fname[--n]; + buff[--i] = '/'; + } + } + tp = buff; + if (res == FR_OK) { +#if _VOLUMES >= 2 + *tp++ = '0' + CurrVol; /* Put drive number */ + *tp++ = ':'; +#endif + if (i == len) { /* Root-directory */ + *tp++ = '/'; + } else { /* Sub-directroy */ + do /* Add stacked path str */ + *tp++ = buff[i++]; + while (i < len); + } + } + *tp = 0; + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + +#endif /* _FS_RPATH >= 2 */ +#endif /* _FS_RPATH >= 1 */ + + + +#if _FS_MINIMIZE <= 2 +/*-----------------------------------------------------------------------*/ +/* Seek File R/W Pointer */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_lseek ( + FIL* fp, /* Pointer to the file object */ + FSIZE_t ofs /* File pointer from top of file */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst, bcs, nsect; + FSIZE_t ifptr; +#if _USE_FASTSEEK + DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl; +#endif + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res == FR_OK) res = (FRESULT)fp->err; +#if _FS_EXFAT && !_FS_READONLY + if (res == FR_OK && fs->fs_type == FS_EXFAT) { + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } +#endif + if (res != FR_OK) LEAVE_FF(fs, res); + +#if _USE_FASTSEEK + if (fp->cltbl) { /* Fast seek */ + if (ofs == CREATE_LINKMAP) { /* Create CLMT */ + tbl = fp->cltbl; + tlen = *tbl++; ulen = 2; /* Given table size and required table size */ + cl = fp->obj.sclust; /* Origin of the chain */ + if (cl) { + do { + /* Get a fragment */ + tcl = cl; ncl = 0; ulen += 2; /* Top, length and used items */ + do { + pcl = cl; ncl++; + cl = get_fat(&fp->obj, cl); + if (cl <= 1) ABORT(fs, FR_INT_ERR); + if (cl == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + } while (cl == pcl + 1); + if (ulen <= tlen) { /* Store the length and top of the fragment */ + *tbl++ = ncl; *tbl++ = tcl; + } + } while (cl < fs->n_fatent); /* Repeat until end of chain */ + } + *fp->cltbl = ulen; /* Number of items used */ + if (ulen <= tlen) { + *tbl = 0; /* Terminate table */ + } else { + res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */ + } + } else { /* Fast seek */ + if (ofs > fp->obj.objsize) ofs = fp->obj.objsize; /* Clip offset at the file size */ + fp->fptr = ofs; /* Set file pointer */ + if (ofs) { + fp->clust = clmt_clust(fp, ofs - 1); + dsc = clust2sect(fs, fp->clust); + if (!dsc) ABORT(fs, FR_INT_ERR); + dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1); + if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */ +#if !_FS_TINY +#if !_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */ +#endif + fp->sect = dsc; + } + } + } + } else +#endif + + /* Normal Seek */ + { +#if _FS_EXFAT + if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4GiB-1 if at FATxx */ +#endif + if (ofs > fp->obj.objsize && (_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */ + ofs = fp->obj.objsize; + } + ifptr = fp->fptr; + fp->fptr = nsect = 0; + if (ofs) { + bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */ + if (ifptr > 0 && + (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */ + fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1); /* start from the current cluster */ + ofs -= fp->fptr; + clst = fp->clust; + } else { /* When seek to back cluster, */ + clst = fp->obj.sclust; /* start from the first cluster */ +#if !_FS_READONLY + if (clst == 0) { /* If no cluster chain, create a new chain */ + clst = create_chain(&fp->obj, 0); + if (clst == 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->obj.sclust = clst; + } +#endif + fp->clust = clst; + } + if (clst != 0) { + while (ofs > bcs) { /* Cluster following loop */ + ofs -= bcs; fp->fptr += bcs; +#if !_FS_READONLY + if (fp->flag & FA_WRITE) { /* Check if in write mode or not */ + if (_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; + } + clst = create_chain(&fp->obj, clst); /* Follow chain with forceed stretch */ + if (clst == 0) { /* Clip file size in case of disk full */ + ofs = 0; break; + } + } else +#endif + { + clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */ + } + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR); + fp->clust = clst; + } + fp->fptr += ofs; + if (ofs % SS(fs)) { + nsect = clust2sect(fs, clst); /* Current sector */ + if (!nsect) ABORT(fs, FR_INT_ERR); + nsect += (DWORD)(ofs / SS(fs)); + } + } + } + if (!_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */ + fp->obj.objsize = fp->fptr; + fp->flag |= FA_MODIFIED; + } + if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */ +#if !_FS_TINY +#if !_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ +#endif + fp->sect = nsect; + } + } + + LEAVE_FF(fs, res); +} + + + +#if _FS_MINIMIZE <= 1 +/*-----------------------------------------------------------------------*/ +/* Create a Directory Object */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_opendir ( + DIR* dp, /* Pointer to directory object to create */ + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + FATFS *fs; + _FDID *obj; + DEF_NAMBUF + + + if (!dp) return FR_INVALID_OBJECT; + + /* Get logical drive */ + obj = &dp->obj; + res = find_volume(&path, &fs, 0); + if (res == FR_OK) { + obj->fs = fs; + INIT_NAMBUF(fs); + res = follow_path(dp, path); /* Follow the path to the directory */ + if (res == FR_OK) { /* Follow completed */ + if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */ + if (obj->attr & AM_DIR) { /* This object is a sub-directory */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + obj->c_scl = obj->sclust; /* Get containing directory inforamation */ + obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; + obj->c_ofs = dp->blk_ofs; + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object allocation info */ + obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; + } else +#endif + { + obj->sclust = ld_clust(fs, dp->dir); /* Get object allocation info */ + } + } else { /* This object is a file */ + res = FR_NO_PATH; + } + } + if (res == FR_OK) { + obj->id = fs->id; + res = dir_sdi(dp, 0); /* Rewind directory */ +#if _FS_LOCK != 0 + if (res == FR_OK) { + if (obj->sclust) { + obj->lockid = inc_lock(dp, 0); /* Lock the sub directory */ + if (!obj->lockid) res = FR_TOO_MANY_OPEN_FILES; + } else { + obj->lockid = 0; /* Root directory need not to be locked */ + } + } +#endif + } + } + FREE_NAMBUF(); + if (res == FR_NO_FILE) res = FR_NO_PATH; + } + if (res != FR_OK) obj->fs = 0; /* Invalidate the directory object if function faild */ + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Close Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_closedir ( + DIR *dp /* Pointer to the directory object to be closed */ +) +{ + FRESULT res; + FATFS *fs; + + + res = validate(&dp->obj, &fs); /* Check validity of the file object */ + if (res == FR_OK) { +#if _FS_LOCK != 0 + if (dp->obj.lockid) { /* Decrement sub-directory open counter */ + res = dec_lock(dp->obj.lockid); + } + if (res == FR_OK) +#endif + { + dp->obj.fs = 0; /* Invalidate directory object */ + } +#if _FS_REENTRANT + unlock_fs(fs, FR_OK); /* Unlock volume */ +#endif + } + return res; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Read Directory Entries in Sequence */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_readdir ( + DIR* dp, /* Pointer to the open directory object */ + FILINFO* fno /* Pointer to file information to return */ +) +{ + FRESULT res; + FATFS *fs; + DEF_NAMBUF + + + res = validate(&dp->obj, &fs); /* Check validity of the directory object */ + if (res == FR_OK) { + if (!fno) { + res = dir_sdi(dp, 0); /* Rewind the directory object */ + } else { + INIT_NAMBUF(fs); + res = dir_read(dp, 0); /* Read an item */ + if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */ + if (res == FR_OK) { /* A valid entry is found */ + get_fileinfo(dp, fno); /* Get the object information */ + res = dir_next(dp, 0); /* Increment index for next */ + if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory now */ + } + FREE_NAMBUF(); + } + } + LEAVE_FF(fs, res); +} + + + +#if _USE_FIND +/*-----------------------------------------------------------------------*/ +/* Find Next File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_findnext ( + DIR* dp, /* Pointer to the open directory object */ + FILINFO* fno /* Pointer to the file information structure */ +) +{ + FRESULT res; + + + for (;;) { + res = f_readdir(dp, fno); /* Get a directory item */ + if (res != FR_OK || !fno || !fno->fname[0]) break; /* Terminate if any error or end of directory */ + if (pattern_matching(dp->pat, fno->fname, 0, 0)) break; /* Test for the file name */ +#if _USE_LFN != 0 && _USE_FIND == 2 + if (pattern_matching(dp->pat, fno->altname, 0, 0)) break; /* Test for alternative name if exist */ +#endif + } + return res; +} + + + +/*-----------------------------------------------------------------------*/ +/* Find First File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_findfirst ( + DIR* dp, /* Pointer to the blank directory object */ + FILINFO* fno, /* Pointer to the file information structure */ + const TCHAR* path, /* Pointer to the directory to open */ + const TCHAR* pattern /* Pointer to the matching pattern */ +) +{ + FRESULT res; + + + dp->pat = pattern; /* Save pointer to pattern string */ + res = f_opendir(dp, path); /* Open the target directory */ + if (res == FR_OK) { + res = f_findnext(dp, fno); /* Find the first item */ + } + return res; +} + +#endif /* _USE_FIND */ + + + +#if _FS_MINIMIZE == 0 +/*-----------------------------------------------------------------------*/ +/* Get File Status */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_stat ( + const TCHAR* path, /* Pointer to the file path */ + FILINFO* fno /* Pointer to file information to return */ +) +{ + FRESULT res; + DIR dj; + DEF_NAMBUF + + + /* Get logical drive */ + res = find_volume(&path, &dj.obj.fs, 0); + if (res == FR_OK) { + INIT_NAMBUF(dj.obj.fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) { /* Follow completed */ + if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */ + res = FR_INVALID_NAME; + } else { /* Found an object */ + if (fno) get_fileinfo(&dj, fno); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(dj.obj.fs, res); +} + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Get Number of Free Clusters */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_getfree ( + const TCHAR* path, /* Path name of the logical drive number */ + DWORD* nclst, /* Pointer to a variable to return number of free clusters */ + FATFS** fatfs /* Pointer to return pointer to corresponding file system object */ +) +{ + FRESULT res; + FATFS *fs; + DWORD nfree, clst, sect, stat; + UINT i; + BYTE *p; + _FDID obj; + + + /* Get logical drive */ + res = find_volume(&path, &fs, 0); + if (res == FR_OK) { + *fatfs = fs; /* Return ptr to the fs object */ + /* If free_clst is valid, return it without full cluster scan */ + if (fs->free_clst <= fs->n_fatent - 2) { + *nclst = fs->free_clst; + } else { + /* Get number of free clusters */ + nfree = 0; + if (fs->fs_type == FS_FAT12) { /* FAT12: Sector unalighed FAT entries */ + clst = 2; obj.fs = fs; + do { + stat = get_fat(&obj, clst); + if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (stat == 1) { res = FR_INT_ERR; break; } + if (stat == 0) nfree++; + } while (++clst < fs->n_fatent); + } else { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* exFAT: Scan bitmap table */ + BYTE bm; + UINT b; + + clst = fs->n_fatent - 2; + sect = fs->database; + i = 0; + do { + if (i == 0 && (res = move_window(fs, sect++)) != FR_OK) break; + for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { + if (!(bm & 1)) nfree++; + bm >>= 1; + } + i = (i + 1) % SS(fs); + } while (clst); + } else +#endif + { /* FAT16/32: Sector alighed FAT entries */ + clst = fs->n_fatent; sect = fs->fatbase; + i = 0; p = 0; + do { + if (i == 0) { + res = move_window(fs, sect++); + if (res != FR_OK) break; + p = fs->win; + i = SS(fs); + } + if (fs->fs_type == FS_FAT16) { + if (ld_word(p) == 0) nfree++; + p += 2; i -= 2; + } else { + if ((ld_dword(p) & 0x0FFFFFFF) == 0) nfree++; + p += 4; i -= 4; + } + } while (--clst); + } + } + *nclst = nfree; /* Return the free clusters */ + fs->free_clst = nfree; /* Now free_clst is valid */ + fs->fsi_flag |= 1; /* FSInfo is to be updated */ + } + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Truncate File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_truncate ( + FIL* fp /* Pointer to the file object */ +) +{ + FRESULT res; + FATFS *fs; + DWORD ncl; + + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); + if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + if (fp->fptr < fp->obj.objsize) { /* Process when fptr is not on the eof */ + if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ + res = remove_chain(&fp->obj, fp->obj.sclust, 0); + fp->obj.sclust = 0; + } else { /* When truncate a part of the file, remove remaining clusters */ + ncl = get_fat(&fp->obj, fp->clust); + res = FR_OK; + if (ncl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (ncl == 1) res = FR_INT_ERR; + if (res == FR_OK && ncl < fs->n_fatent) { + res = remove_chain(&fp->obj, ncl, fp->clust); + } + } + fp->obj.objsize = fp->fptr; /* Set file size to current R/W point */ + fp->flag |= FA_MODIFIED; +#if !_FS_TINY + if (res == FR_OK && (fp->flag & FA_DIRTY)) { + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) { + res = FR_DISK_ERR; + } else { + fp->flag &= (BYTE)~FA_DIRTY; + } + } +#endif + if (res != FR_OK) ABORT(fs, res); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Delete a File/Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_unlink ( + const TCHAR* path /* Pointer to the file or directory path */ +) +{ + FRESULT res; + DIR dj, sdj; + DWORD dclst = 0; + FATFS *fs; +#if _FS_EXFAT + _FDID obj; +#endif + DEF_NAMBUF + + + /* Get logical drive */ + res = find_volume(&path, &fs, FA_WRITE); + dj.obj.fs = fs; + if (res == FR_OK) { + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { + res = FR_INVALID_NAME; /* Cannot remove dot entry */ + } +#if _FS_LOCK != 0 + if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ +#endif + if (res == FR_OK) { /* The object is accessible */ + if (dj.fn[NSFLAG] & NS_NONAME) { + res = FR_INVALID_NAME; /* Cannot remove the origin directory */ + } else { + if (dj.obj.attr & AM_RDO) { + res = FR_DENIED; /* Cannot remove R/O object */ + } + } + if (res == FR_OK) { +#if _FS_EXFAT + obj.fs = fs; + if (fs->fs_type == FS_EXFAT) { + obj.sclust = dclst = ld_dword(fs->dirbuf + XDIR_FstClus); + obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + } else +#endif + { + dclst = ld_clust(fs, dj.dir); + } + if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ +#if _FS_RPATH != 0 + if (dclst == fs->cdir) { /* Is it the current directory? */ + res = FR_DENIED; + } else +#endif + { + sdj.obj.fs = fs; /* Open the sub-directory */ + sdj.obj.sclust = dclst; +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + sdj.obj.objsize = obj.objsize; + sdj.obj.stat = obj.stat; + } +#endif + res = dir_sdi(&sdj, 0); + if (res == FR_OK) { + res = dir_read(&sdj, 0); /* Read an item */ + if (res == FR_OK) res = FR_DENIED; /* Not empty? */ + if (res == FR_NO_FILE) res = FR_OK; /* Empty? */ + } + } + } + } + if (res == FR_OK) { + res = dir_remove(&dj); /* Remove the directory entry */ + if (res == FR_OK && dclst) { /* Remove the cluster chain if exist */ +#if _FS_EXFAT + res = remove_chain(&obj, dclst, 0); +#else + res = remove_chain(&dj.obj, dclst, 0); +#endif + } + if (res == FR_OK) res = sync_fs(fs); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Create a Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mkdir ( + const TCHAR* path /* Pointer to the directory path */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + BYTE *dir; + UINT n; + DWORD dsc, dcl, pcl, tm; + DEF_NAMBUF + + + /* Get logical drive */ + res = find_volume(&path, &fs, FA_WRITE); + dj.obj.fs = fs; + if (res == FR_OK) { + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK) res = FR_EXIST; /* Any object with same name is already existing */ + if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT)) { + res = FR_INVALID_NAME; + } + if (res == FR_NO_FILE) { /* Can create a new directory */ + dcl = create_chain(&dj.obj, 0); /* Allocate a cluster for the new directory table */ + dj.obj.objsize = (DWORD)fs->csize * SS(fs); + res = FR_OK; + if (dcl == 0) res = FR_DENIED; /* No space to allocate a new cluster */ + if (dcl == 1) res = FR_INT_ERR; + if (dcl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (res == FR_OK) res = sync_window(fs); /* Flush FAT */ + tm = GET_FATTIME(); + if (res == FR_OK) { /* Initialize the new directory table */ + dsc = clust2sect(fs, dcl); + dir = fs->win; + mem_set(dir, 0, SS(fs)); + if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { + mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */ + dir[DIR_Name] = '.'; + dir[DIR_Attr] = AM_DIR; + st_dword(dir + DIR_ModTime, tm); + st_clust(fs, dir, dcl); + mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */ + dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust; + if (fs->fs_type == FS_FAT32 && pcl == fs->dirbase) pcl = 0; + st_clust(fs, dir + SZDIRE, pcl); + } + for (n = fs->csize; n; n--) { /* Write dot entries and clear following sectors */ + fs->winsect = dsc++; + fs->wflag = 1; + res = sync_window(fs); + if (res != FR_OK) break; + mem_set(dir, 0, SS(fs)); + } + } + if (res == FR_OK) { + res = dir_register(&dj); /* Register the object to the directoy */ + } + if (res == FR_OK) { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ + st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */ + st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */ + st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */ + st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize); + fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag (contiguous) */ + fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */ + res = store_xdir(&dj); + } else +#endif + { + dir = dj.dir; + st_dword(dir + DIR_ModTime, tm); /* Created time */ + st_clust(fs, dir, dcl); /* Table start cluster */ + dir[DIR_Attr] = AM_DIR; /* Attribute */ + fs->wflag = 1; + } + if (res == FR_OK) { + res = sync_fs(fs); + } + } else { + remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Rename a File/Directory */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_rename ( + const TCHAR* path_old, /* Pointer to the object name to be renamed */ + const TCHAR* path_new /* Pointer to the new name */ +) +{ + FRESULT res; + DIR djo, djn; + FATFS *fs; + BYTE buf[_FS_EXFAT ? SZDIRE * 2 : 24], *dir; + DWORD dw; + DEF_NAMBUF + + + get_ldnumber(&path_new); /* Snip drive number of new name off */ + res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ + if (res == FR_OK) { + djo.obj.fs = fs; + INIT_NAMBUF(fs); + res = follow_path(&djo, path_old); /* Check old object */ + if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ +#if _FS_LOCK != 0 + if (res == FR_OK) { + res = chk_lock(&djo, 2); + } +#endif + if (res == FR_OK) { /* Object to be renamed is found */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* At exFAT */ + BYTE nf, nn; + WORD nh; + + mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */ + mem_cpy(&djn, &djo, sizeof djo); + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) { /* Is new name already in use by any other object? */ + res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; + } + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ + if (res == FR_OK) { + nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName]; + nh = ld_word(fs->dirbuf + XDIR_NameHash); + mem_cpy(fs->dirbuf, buf, SZDIRE * 2); + fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; + st_word(fs->dirbuf + XDIR_NameHash, nh); +/* Start of critical section where an interruption can cause a cross-link */ + res = store_xdir(&djn); + } + } + } else +#endif + { /* At FAT12/FAT16/FAT32 */ + mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about the object except name */ + mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */ + res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */ + if (res == FR_OK) { /* Is new name already in use by any other object? */ + res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST; + } + if (res == FR_NO_FILE) { /* It is a valid path and no name collision */ + res = dir_register(&djn); /* Register the new entry */ + if (res == FR_OK) { + dir = djn.dir; /* Copy information about object except name */ + mem_cpy(dir + 13, buf + 2, 19); + dir[DIR_Attr] = buf[0] | AM_ARC; + fs->wflag = 1; + if ((dir[DIR_Attr] & AM_DIR) && djo.obj.sclust != djn.obj.sclust) { /* Update .. entry in the sub-directory if needed */ + dw = clust2sect(fs, ld_clust(fs, dir)); + if (!dw) { + res = FR_INT_ERR; + } else { +/* Start of critical section where an interruption can cause a cross-link */ + res = move_window(fs, dw); + dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ + if (res == FR_OK && dir[1] == '.') { + st_clust(fs, dir, djn.obj.sclust); + fs->wflag = 1; + } + } + } + } + } + } + if (res == FR_OK) { + res = dir_remove(&djo); /* Remove old entry */ + if (res == FR_OK) { + res = sync_fs(fs); + } + } +/* End of the critical section */ + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + +#endif /* !_FS_READONLY */ +#endif /* _FS_MINIMIZE == 0 */ +#endif /* _FS_MINIMIZE <= 1 */ +#endif /* _FS_MINIMIZE <= 2 */ + + + +#if _USE_CHMOD && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Change Attribute */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_chmod ( + const TCHAR* path, /* Pointer to the file path */ + BYTE attr, /* Attribute bits */ + BYTE mask /* Attribute mask to change */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + DEF_NAMBUF + + + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + dj.obj.fs = fs; + if (res == FR_OK) { + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ + if (res == FR_OK) { + mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */ +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + fs->dirbuf[XDIR_Attr] = (attr & mask) | (fs->dirbuf[XDIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + res = store_xdir(&dj); + } else +#endif + { + dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ + fs->wflag = 1; + } + if (res == FR_OK) { + res = sync_fs(fs); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Change Timestamp */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_utime ( + const TCHAR* path, /* Pointer to the file/directory name */ + const FILINFO* fno /* Pointer to the time stamp to be set */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + DEF_NAMBUF + + + res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */ + dj.obj.fs = fs; + if (res == FR_OK) { + INIT_NAMBUF(fs); + res = follow_path(&dj, path); /* Follow the file path */ + if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */ + if (res == FR_OK) { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + res = store_xdir(&dj); + } else +#endif + { + st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); + fs->wflag = 1; + } + if (res == FR_OK) { + res = sync_fs(fs); + } + } + FREE_NAMBUF(); + } + + LEAVE_FF(fs, res); +} + +#endif /* _USE_CHMOD && !_FS_READONLY */ + + + +#if _USE_LABEL +/*-----------------------------------------------------------------------*/ +/* Get Volume Label */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_getlabel ( + const TCHAR* path, /* Path name of the logical drive number */ + TCHAR* label, /* Pointer to a buffer to return the volume label */ + DWORD* vsn /* Pointer to a variable to return the volume serial number */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + UINT si, di; +#if _LFN_UNICODE || _FS_EXFAT + WCHAR w; +#endif + + /* Get logical drive */ + res = find_volume(&path, &fs, 0); + + /* Get volume label */ + if (res == FR_OK && label) { + dj.obj.fs = fs; dj.obj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = dir_read(&dj, 1); /* Find a volume label entry */ + if (res == FR_OK) { +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + for (si = di = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ + w = ld_word(dj.dir + XDIR_Label + si * 2); +#if _LFN_UNICODE + label[di++] = w; +#else + w = ff_convert(w, 0); /* Unicode -> OEM */ + if (w == 0) w = '?'; /* Replace wrong character */ + if (_DF1S && w >= 0x100) label[di++] = (char)(w >> 8); + label[di++] = (char)w; +#endif + } + label[di] = 0; + } else +#endif + { + si = di = 0; /* Extract volume label from AM_VOL entry with code comversion */ + do { +#if _LFN_UNICODE + w = (si < 11) ? dj.dir[si++] : ' '; + if (IsDBCS1(w) && si < 11 && IsDBCS2(dj.dir[si])) { + w = w << 8 | dj.dir[si++]; + } + label[di++] = ff_convert(w, 1); /* OEM -> Unicode */ +#else + label[di++] = dj.dir[si++]; +#endif + } while (di < 11); + do { /* Truncate trailing spaces */ + label[di] = 0; + if (di == 0) break; + } while (label[--di] == ' '); + } + } + } + if (res == FR_NO_FILE) { /* No label entry and return nul string */ + label[0] = 0; + res = FR_OK; + } + } + + /* Get volume serial number */ + if (res == FR_OK && vsn) { + res = move_window(fs, fs->volbase); + if (res == FR_OK) { + switch (fs->fs_type) { + case FS_EXFAT: + di = BPB_VolIDEx; break; + + case FS_FAT32: + di = BS_VolID32; break; + + default: + di = BS_VolID; + } + *vsn = ld_dword(fs->win + di); + } + } + + LEAVE_FF(fs, res); +} + + + +#if !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Set Volume Label */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_setlabel ( + const TCHAR* label /* Pointer to the volume label to set */ +) +{ + FRESULT res; + DIR dj; + FATFS *fs; + BYTE dirvn[22]; + UINT i, j, slen; + WCHAR w; + static const char badchr[] = "\"*+,.:;<=>\?[]|\x7F"; + + + /* Get logical drive */ + res = find_volume(&label, &fs, FA_WRITE); + if (res != FR_OK) LEAVE_FF(fs, res); + dj.obj.fs = fs; + + /* Get length of given volume label */ + for (slen = 0; (UINT)label[slen] >= ' '; slen++) ; /* Get name length */ + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ + for (i = j = 0; i < slen; ) { /* Create volume label in directory form */ + w = label[i++]; +#if !_LFN_UNICODE + if (IsDBCS1(w)) { + w = (i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; + } + w = ff_convert(w, 1); +#endif + if (w == 0 || chk_chr(badchr, w) || j == 22) { /* Check validity check validity of the volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + st_word(dirvn + j, w); j += 2; + } + slen = j; + } else +#endif + { /* On the FAT12/16/32 volume */ + for ( ; slen && label[slen - 1] == ' '; slen--) ; /* Remove trailing spaces */ + if (slen) { /* Is there a volume label to be set? */ + dirvn[0] = 0; i = j = 0; /* Create volume label in directory form */ + do { +#if _LFN_UNICODE + w = ff_convert(ff_wtoupper(label[i++]), 0); +#else + w = (BYTE)label[i++]; + if (IsDBCS1(w)) { + w = (j < 10 && i < slen && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0; + } +#if _USE_LFN != 0 + w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0); +#else + if (IsLower(w)) w -= 0x20; /* To upper ASCII characters */ +#ifdef _EXCVT + if (w >= 0x80) w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */ +#else + if (!_DF1S && w >= 0x80) w = 0; /* Reject extended characters (ASCII cfg) */ +#endif +#endif +#endif + if (w == 0 || chk_chr(badchr, w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) { /* Reject invalid characters for volume label */ + LEAVE_FF(fs, FR_INVALID_NAME); + } + if (w >= 0x100) dirvn[j++] = (BYTE)(w >> 8); + dirvn[j++] = (BYTE)w; + } while (i < slen); + while (j < 11) dirvn[j++] = ' '; /* Fill remaining name field */ + if (dirvn[0] == DDEM) LEAVE_FF(fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */ + } + } + + /* Set volume label */ + dj.obj.sclust = 0; /* Open root directory */ + res = dir_sdi(&dj, 0); + if (res == FR_OK) { + res = dir_read(&dj, 1); /* Get volume label entry */ + if (res == FR_OK) { + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2); /* Change the volume label */ + mem_cpy(dj.dir + XDIR_Label, dirvn, slen); + } else { + if (slen) { + mem_cpy(dj.dir, dirvn, 11); /* Change the volume label */ + } else { + dj.dir[DIR_Name] = DDEM; /* Remove the volume label */ + } + } + fs->wflag = 1; + res = sync_fs(fs); + } else { /* No volume label entry is found or error */ + if (res == FR_NO_FILE) { + res = FR_OK; + if (slen) { /* Create a volume label entry */ + res = dir_alloc(&dj, 1); /* Allocate an entry */ + if (res == FR_OK) { + mem_set(dj.dir, 0, SZDIRE); /* Clear the entry */ + if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { + dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */ + dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2); + mem_cpy(dj.dir + XDIR_Label, dirvn, slen); + } else { + dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */ + mem_cpy(dj.dir, dirvn, 11); + } + fs->wflag = 1; + res = sync_fs(fs); + } + } + } + } + } + + LEAVE_FF(fs, res); +} + +#endif /* !_FS_READONLY */ +#endif /* _USE_LABEL */ + + + +#if _USE_EXPAND && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Allocate a Contiguous Blocks to the File */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_expand ( + FIL* fp, /* Pointer to the file object */ + FSIZE_t fsz, /* File size to be expanded to */ + BYTE opt /* Operation mode 0:Find and prepare or 1:Find and allocate */ +) +{ + FRESULT res; + FATFS *fs; + DWORD n, clst, stcl, scl, ncl, tcl, lclst; + + + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); + if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); +#if _FS_EXFAT + if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */ +#endif + n = (DWORD)fs->csize * SS(fs); /* Cluster size */ + tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0); /* Number of clusters required */ + stcl = fs->last_clst; lclst = 0; + if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2; + +#if _FS_EXFAT + if (fs->fs_type == FS_EXFAT) { + scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ + if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ + if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ + res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ + lclst = scl + tcl - 1; + } else { /* Set it as suggested point for next allocation */ + lclst = scl - 1; + } + } + } else +#endif + { + scl = clst = stcl; ncl = 0; + for (;;) { /* Find a contiguous cluster block */ + n = get_fat(&fp->obj, clst); + if (++clst >= fs->n_fatent) clst = 2; + if (n == 1) { res = FR_INT_ERR; break; } + if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (n == 0) { /* Is it a free cluster? */ + if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ + } else { + scl = clst; ncl = 0; /* Not a free cluster */ + } + if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ + } + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ + for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ + res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); + if (res != FR_OK) break; + lclst = clst; + } + } else { /* Set it as suggested point for next allocation */ + lclst = scl - 1; + } + } + } + + if (res == FR_OK) { + fs->last_clst = lclst; /* Set suggested start cluster to start next */ + if (opt) { /* Is it allocated now? */ + fp->obj.sclust = scl; /* Update object allocation information */ + fp->obj.objsize = fsz; + if (_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ + fp->flag |= FA_MODIFIED; + if (fs->free_clst <= fs->n_fatent - 2) { /* Update FSINFO */ + fs->free_clst -= tcl; + fs->fsi_flag |= 1; + } + } + } + + LEAVE_FF(fs, res); +} + +#endif /* _USE_EXPAND && !_FS_READONLY */ + + + +#if _USE_FORWARD +/*-----------------------------------------------------------------------*/ +/* Forward data to the stream directly */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_forward ( + FIL* fp, /* Pointer to the file object */ + UINT (*func)(const BYTE*,UINT), /* Pointer to the streaming function */ + UINT btf, /* Number of bytes to forward */ + UINT* bf /* Pointer to number of bytes forwarded */ +) +{ + FRESULT res; + FATFS *fs; + DWORD clst, sect; + FSIZE_t remain; + UINT rcnt, csect; + BYTE *dbuf; + + + *bf = 0; /* Clear transfer byte counter */ + res = validate(&fp->obj, &fs); /* Check validity of the file object */ + if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); + if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ + + remain = fp->obj.objsize - fp->fptr; + if (btf > remain) btf = (UINT)remain; /* Truncate btf by remaining bytes */ + + for ( ; btf && (*func)(0, 0); /* Repeat until all data transferred or stream goes busy */ + fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) { + csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */ + if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */ + if (csect == 0) { /* On the cluster boundary? */ + clst = (fp->fptr == 0) ? /* On the top of the file? */ + fp->obj.sclust : get_fat(&fp->obj, fp->clust); + if (clst <= 1) ABORT(fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); + fp->clust = clst; /* Update current cluster */ + } + } + sect = clust2sect(fs, fp->clust); /* Get current data sector */ + if (!sect) ABORT(fs, FR_INT_ERR); + sect += csect; +#if _FS_TINY + if (move_window(fs, sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window to the file data */ + dbuf = fs->win; +#else + if (fp->sect != sect) { /* Fill sector cache with file data */ +#if !_FS_READONLY + if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */ + if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + fp->flag &= (BYTE)~FA_DIRTY; + } +#endif + if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); + } + dbuf = fp->buf; +#endif + fp->sect = sect; + rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */ + if (rcnt > btf) rcnt = btf; /* Clip it by btr if needed */ + rcnt = (*func)(dbuf + ((UINT)fp->fptr % SS(fs)), rcnt); /* Forward the file data */ + if (!rcnt) ABORT(fs, FR_INT_ERR); + } + + LEAVE_FF(fs, FR_OK); +} +#endif /* _USE_FORWARD */ + + + +#if _USE_MKFS && !_FS_READONLY +/*-----------------------------------------------------------------------*/ +/* Create an FAT/exFAT volume */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_mkfs ( + const TCHAR* path, /* Logical drive number */ + BYTE opt, /* Format option */ + DWORD au, /* Size of allocation unit (cluster) [byte] */ + void* work, /* Pointer to working buffer */ + UINT len /* Size of working buffer */ +) +{ + const UINT n_fats = 1; /* Number of FATs for FAT12/16/32 volume (1 or 2) */ + const UINT n_rootdir = 512; /* Number of root directory entries for FAT12/16 volume */ + static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT12/16 volume (4Ks unit) */ + static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ + BYTE fmt, sys, *buf, *pte, pdrv, part; + WORD ss; + DWORD szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n; + DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */ + DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */ + UINT i; + int vol; + DSTATUS stat; +#if _USE_TRIM || _FS_EXFAT + DWORD tbl[3]; +#endif + + + /* Check mounted drive and clear work area */ + vol = get_ldnumber(&path); /* Get target logical drive */ + if (vol < 0) return FR_INVALID_DRIVE; + if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the volume */ + pdrv = LD2PD(vol); /* Physical drive */ + part = LD2PT(vol); /* Partition (0:create as new, 1-4:get from partition table) */ + + /* Check physical drive status */ + stat = disk_initialize(pdrv); + if (stat & STA_NOINIT) return FR_NOT_READY; + if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; + if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Erase block to align data area */ +#if _MAX_SS != _MIN_SS /* Get sector size of the medium if variable sector size cfg. */ + if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; + if (ss > _MAX_SS || ss < _MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; +#else + ss = _MAX_SS; +#endif + if ((au != 0 && au < ss) || au > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */ + au /= ss; /* Cluster size in unit of sector */ + + /* Get working buffer */ + buf = (BYTE*)work; /* Working buffer */ + sz_buf = len / ss; /* Size of working buffer (sector) */ + szb_buf = sz_buf * ss; /* Size of working buffer (byte) */ + if (!szb_buf) return FR_MKFS_ABORTED; + + /* Determine where the volume to be located (b_vol, sz_vol) */ + if (_MULTI_PARTITION && part != 0) { + /* Get partition information from partition table in the MBR */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Load MBR */ + if (ld_word(buf + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; /* Check if MBR is valid */ + pte = buf + (MBR_Table + (part - 1) * SZ_PTE); + if (!pte[PTE_System]) return FR_MKFS_ABORTED; /* No partition? */ + b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */ + sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */ + } else { + /* Create a single-partition in this function */ + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) return FR_DISK_ERR; + b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ + if (sz_vol < b_vol) return FR_MKFS_ABORTED; + sz_vol -= b_vol; /* Volume size */ + } + if (sz_vol < 128) return FR_MKFS_ABORTED; /* Check if volume size is >=128s */ + + /* Pre-determine the FAT type */ + do { + if (_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */ + if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) { /* exFAT only, vol >= 64Ms or au > 128s ? */ + fmt = FS_EXFAT; break; + } + } + if (au > 128) return FR_INVALID_PARAMETER; /* Too large au for FAT/FAT32 */ + if (opt & FM_FAT32) { /* FAT32 possible? */ + if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */ + fmt = FS_FAT32; break; + } + } + if (!(opt & FM_FAT)) return FR_INVALID_PARAMETER; /* no-FAT? */ + fmt = FS_FAT16; + } while (0); + +#if _FS_EXFAT + if (fmt == FS_EXFAT) { /* Create an exFAT volume */ + DWORD szb_bit, szb_case, sum, nb, cl; + WCHAR ch, si; + UINT j, st; + BYTE b; + + if (sz_vol < 0x1000) return FR_MKFS_ABORTED; /* Too small volume? */ +#if _USE_TRIM + tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area may be erased */ + disk_ioctl(pdrv, CTRL_TRIM, tbl); +#endif + /* Determine FAT location, data location and number of clusters */ + if (!au) { /* au auto-selection */ + au = 8; + if (sz_vol >= 0x80000) au = 64; /* >= 512Ks */ + if (sz_vol >= 0x4000000) au = 256; /* >= 64Ms */ + } + b_fat = b_vol + 32; /* FAT start at offset 32 */ + sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ + b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */ + if (b_data >= sz_vol / 2) return FR_MKFS_ABORTED; /* Too small volume? */ + n_clst = (sz_vol - (b_data - b_vol)) / au; /* Number of clusters */ + if (n_clst <16) return FR_MKFS_ABORTED; /* Too few clusters? */ + if (n_clst > MAX_EXFAT) return FR_MKFS_ABORTED; /* Too many clusters? */ + + szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */ + tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of allocation bitmap clusters */ + + /* Create a compressed up-case table */ + sect = b_data + au * tbl[0]; /* Table start sector */ + sum = 0; /* Table checksum to be stored in the 82 entry */ + st = si = i = j = szb_case = 0; + do { + switch (st) { + case 0: + ch = ff_wtoupper(si); /* Get an up-case char */ + if (ch != si) { + si++; break; /* Store the up-case char if exist */ + } + for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ; /* Get run length of no-case block */ + if (j >= 128) { + ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */ + } + st = 1; /* Do not compress short run */ + /* go to next case */ + case 1: + ch = si++; /* Fill the short run */ + if (--j == 0) st = 0; + break; + + default: + ch = (WCHAR)j; si += j; /* Number of chars to skip */ + st = 0; + } + sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */ + sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum); + i += 2; szb_case += 2; + if (!si || i == szb_buf) { /* Write buffered data when buffer full or end of process */ + n = (i + ss - 1) / ss; + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + sect += n; i = 0; + } + } while (si); + tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case table clusters */ + tbl[2] = 1; /* Number of root dir clusters */ + + /* Initialize the allocation bitmap */ + sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */ + nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */ + do { + mem_set(buf, 0, szb_buf); + for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ; + for (b = 1; nb && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ; + n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + sect += n; nsect -= n; + } while (nsect); + + /* Initialize the FAT */ + sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */ + j = nb = cl = 0; + do { + mem_set(buf, 0, szb_buf); i = 0; /* Clear work area and reset write index */ + if (cl == 0) { /* Set entry 0 and 1 */ + st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++; + st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++; + } + do { /* Create chains of bitmap, up-case and root dir */ + while (nb && i < szb_buf) { /* Create a chain */ + st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF); + i += 4; cl++; nb--; + } + if (!nb && j < 3) nb = tbl[j++]; /* Next chain */ + } while (nb && i < szb_buf); + n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */ + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + sect += n; nsect -= n; + } while (nsect); + + /* Initialize the root directory */ + mem_set(buf, 0, szb_buf); + buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */ + buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */ + st_dword(buf + SZDIRE * 1 + 20, 2); + st_dword(buf + SZDIRE * 1 + 24, szb_bit); + buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */ + st_dword(buf + SZDIRE * 2 + 4, sum); + st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]); + st_dword(buf + SZDIRE * 2 + 24, szb_case); + sect = b_data + au * (tbl[0] + tbl[1]); nsect = au; /* Start of the root directory and number of sectors */ + do { /* Fill root directory sectors */ + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR; + mem_set(buf, 0, ss); + sect += n; nsect -= n; + } while (nsect); + + /* Create two set of the exFAT VBR blocks */ + sect = b_vol; + for (n = 0; n < 2; n++) { + /* Main record (+0) */ + mem_set(buf, 0, ss); + mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */ + st_dword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */ + st_dword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */ + st_dword(buf + BPB_FatOfsEx, b_fat - b_vol); /* FAT offset [sector] */ + st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */ + st_dword(buf + BPB_DataOfsEx, b_data - b_vol); /* Data offset [sector] */ + st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */ + st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */ + st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */ + st_word(buf + BPB_FSVerEx, 0x100); /* File system version (1.00) */ + for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */ + for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */ + buf[BPB_NumFATsEx] = 1; /* Number of FATs */ + buf[BPB_DrvNumEx] = 0x80; /* Drive number (for int13) */ + st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */ + st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */ + for (i = sum = 0; i < ss; i++) { /* VBR checksum */ + if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum); + } + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + /* Extended bootstrap record (+1..+8) */ + mem_set(buf, 0, ss); + st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */ + for (j = 1; j < 9; j++) { + for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + } + /* OEM/Reserved record (+9..+10) */ + mem_set(buf, 0, ss); + for ( ; j < 11; j++) { + for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + } + /* Sum record (+11) */ + for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */ + if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR; + } + + } else +#endif /* _FS_EXFAT */ + { /* Create an FAT12/16/32 volume */ + do { + pau = au; + /* Pre-determine number of clusters and FAT sub-type */ + if (fmt == FS_FAT32) { /* FAT32 volume */ + if (!pau) { /* au auto-selection */ + n = sz_vol / 0x20000; /* Volume size in unit of 128KS */ + for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */ + } + n_clst = sz_vol / pau; /* Number of clusters */ + sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */ + sz_rsv = 32; /* Number of reserved sectors */ + sz_dir = 0; /* No static directory */ + if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) return FR_MKFS_ABORTED; + } else { /* FAT12/16 volume */ + if (!pau) { /* au auto-selection */ + n = sz_vol / 0x1000; /* Volume size in unit of 4KS */ + for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */ + } + n_clst = sz_vol / pau; + if (n_clst > MAX_FAT12) { + n = n_clst * 2 + 4; /* FAT size [byte] */ + } else { + fmt = FS_FAT12; + n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */ + } + sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */ + sz_rsv = 1; /* Number of reserved sectors */ + sz_dir = (DWORD)n_rootdir * SZDIRE / ss; /* Rootdir size [sector] */ + } + b_fat = b_vol + sz_rsv; /* FAT base */ + b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */ + + /* Align data base to erase block boundary (for flash memory media) */ + n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */ + if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ + sz_rsv += n; b_fat += n; + } else { /* FAT12/16: Expand FAT size */ + sz_fat += n / n_fats; + } + + /* Determine number of clusters and final check of validity of the FAT sub-type */ + if (sz_vol < b_data + pau * 16 - b_vol) return FR_MKFS_ABORTED; /* Too small volume */ + n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau; + if (fmt == FS_FAT32) { + if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32 */ + if (!au && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */ + return FR_MKFS_ABORTED; + } + } + if (fmt == FS_FAT16) { + if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */ + if (!au && (pau * 2) <= 64) { + au = pau * 2; continue; /* Adjust cluster size and retry */ + } + if ((opt & FM_FAT32)) { + fmt = FS_FAT32; continue; /* Switch type to FAT32 and retry */ + } + if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + return FR_MKFS_ABORTED; + } + if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */ + if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */ + return FR_MKFS_ABORTED; + } + } + if (fmt == FS_FAT12 && n_clst > MAX_FAT12) return FR_MKFS_ABORTED; /* Too many clusters for FAT12 */ + + /* Ok, it is the valid cluster configuration */ + break; + } while (1); + +#if _USE_TRIM + tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ + disk_ioctl(pdrv, CTRL_TRIM, tbl); +#endif + /* Create FAT VBR */ + mem_set(buf, 0, ss); + mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */ + st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */ + buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */ + st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */ + buf[BPB_NumFATs] = (BYTE)n_fats; /* Number of FATs */ + st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir)); /* Number of root directory entries */ + if (sz_vol < 0x10000) { + st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */ + } else { + st_dword(buf + BPB_TotSec32, sz_vol); /* Volume size in 32-bit LBA */ + } + buf[BPB_Media] = 0xF8; /* Media descriptor byte */ + st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */ + st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */ + st_dword(buf + BPB_HiddSec, b_vol); /* Volume offset in the physical drive [sector] */ + if (fmt == FS_FAT32) { + st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */ + st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */ + st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */ + st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */ + st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ + buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ + buf[BS_BootSig32] = 0x29; /* Extended boot signature */ + mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ + } else { + st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ + st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ + buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ + buf[BS_BootSig] = 0x29; /* Extended boot signature */ + mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ + } + st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ + if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the VBR sector */ + + /* Create FSINFO record if needed */ + if (fmt == FS_FAT32) { + disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */ + mem_set(buf, 0, ss); + st_dword(buf + FSI_LeadSig, 0x41615252); + st_dword(buf + FSI_StrucSig, 0x61417272); + st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */ + st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */ + st_word(buf + BS_55AA, 0xAA55); + disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */ + disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ + } + + /* Initialize FAT area */ + mem_set(buf, 0, (UINT)szb_buf); + sect = b_fat; /* FAT start sector */ + for (i = 0; i < n_fats; i++) { /* Initialize FATs each */ + if (fmt == FS_FAT32) { + st_dword(buf + 0, 0xFFFFFFF8); /* Entry 0 */ + st_dword(buf + 4, 0xFFFFFFFF); /* Entry 1 */ + st_dword(buf + 8, 0x0FFFFFFF); /* Entry 2 (root directory) */ + } else { + st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* Entry 0 and 1 */ + } + nsect = sz_fat; /* Number of FAT sectors */ + do { /* Fill FAT sectors */ + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR; + mem_set(buf, 0, ss); + sect += n; nsect -= n; + } while (nsect); + } + + /* Initialize root directory (fill with zero) */ + nsect = (fmt == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ + do { + n = (nsect > sz_buf) ? sz_buf : nsect; + if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR; + sect += n; nsect -= n; + } while (nsect); + } + + /* Determine system ID in the partition table */ + if (_FS_EXFAT && fmt == FS_EXFAT) { + sys = 0x07; /* HPFS/NTFS/exFAT */ + } else { + if (fmt == FS_FAT32) { + sys = 0x0C; /* FAT32X */ + } else { + if (sz_vol >= 0x10000) { + sys = 0x06; /* FAT12/16 (>=64KS) */ + } else { + sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 (<64KS) : FAT12 (<64KS) */ + } + } + } + + /* Update partition information */ + if (_MULTI_PARTITION && part != 0) { /* Created in the existing partition */ + /* Update system ID in the partition table */ + if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Read the MBR */ + buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it back to the MBR */ + } else { /* Created as a new single partition */ + if (!(opt & FM_SFD)) { /* Create partition table if in FDISK format */ + mem_set(buf, 0, ss); + st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ + pte = buf + MBR_Table; /* Create partition table for single partition in the drive */ + pte[PTE_Boot] = 0; /* Boot indicator */ + pte[PTE_StHead] = 1; /* Start head */ + pte[PTE_StSec] = 1; /* Start sector */ + pte[PTE_StCyl] = 0; /* Start cylinder */ + pte[PTE_System] = sys; /* System type */ + n = (b_vol + sz_vol) / (63 * 255); /* (End CHS may be invalid) */ + pte[PTE_EdHead] = 254; /* End head */ + pte[PTE_EdSec] = (BYTE)(n >> 2 | 63); /* End sector */ + pte[PTE_EdCyl] = (BYTE)n; /* End cylinder */ + st_dword(pte + PTE_StLba, b_vol); /* Start offset in LBA */ + st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */ + if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */ + } + } + + if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) return FR_DISK_ERR; + + return FR_OK; +} + + + +#if _MULTI_PARTITION +/*-----------------------------------------------------------------------*/ +/* Create partition table on the physical drive */ +/*-----------------------------------------------------------------------*/ + +FRESULT f_fdisk ( + BYTE pdrv, /* Physical drive number */ + const DWORD* szt, /* Pointer to the size table for each partitions */ + void* work /* Pointer to the working buffer */ +) +{ + UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl; + BYTE s_hd, e_hd, *p, *buf = (BYTE*)work; + DSTATUS stat; + DWORD sz_disk, sz_part, s_part; + + + stat = disk_initialize(pdrv); + if (stat & STA_NOINIT) return FR_NOT_READY; + if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; + if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; + + /* Determine the CHS without any consideration of the drive geometry */ + for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; + if (n == 256) n--; + e_hd = n - 1; + sz_cyl = 63 * n; + tot_cyl = sz_disk / sz_cyl; + + /* Create partition table */ + mem_set(buf, 0, _MAX_SS); + p = buf + MBR_Table; b_cyl = 0; + for (i = 0; i < 4; i++, p += SZ_PTE) { + p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; /* Number of cylinders */ + if (!p_cyl) continue; + s_part = (DWORD)sz_cyl * b_cyl; + sz_part = (DWORD)sz_cyl * p_cyl; + if (i == 0) { /* Exclude first track of cylinder 0 */ + s_hd = 1; + s_part += 63; sz_part -= 63; + } else { + s_hd = 0; + } + e_cyl = b_cyl + p_cyl - 1; /* End cylinder */ + if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER; + + /* Set partition table */ + p[1] = s_hd; /* Start head */ + p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */ + p[3] = (BYTE)b_cyl; /* Start cylinder */ + p[4] = 0x07; /* System type (temporary setting) */ + p[5] = e_hd; /* End head */ + p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ + p[7] = (BYTE)e_cyl; /* End cylinder */ + st_dword(p + 8, s_part); /* Start sector in LBA */ + st_dword(p + 12, sz_part); /* Number of sectors */ + + /* Next partition */ + b_cyl += p_cyl; + } + st_word(p, 0xAA55); + + /* Write it to the MBR */ + return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK; +} + +#endif /* _MULTI_PARTITION */ +#endif /* _USE_MKFS && !_FS_READONLY */ + + + + +#if _USE_STRFUNC +/*-----------------------------------------------------------------------*/ +/* Get a string from the file */ +/*-----------------------------------------------------------------------*/ + +TCHAR* f_gets ( + TCHAR* buff, /* Pointer to the string buffer to read */ + int len, /* Size of string buffer (characters) */ + FIL* fp /* Pointer to the file object */ +) +{ + int n = 0; + TCHAR c, *p = buff; + BYTE s[2]; + UINT rc; + + + while (n < len - 1) { /* Read characters until buffer gets filled */ +#if _LFN_UNICODE +#if _STRF_ENCODE == 3 /* Read a character in UTF-8 */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = s[0]; + if (c >= 0x80) { + if (c < 0xC0) continue; /* Skip stray trailer */ + if (c < 0xE0) { /* Two-byte sequence (0x80-0x7FF) */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = (c & 0x1F) << 6 | (s[0] & 0x3F); + if (c < 0x80) c = '?'; /* Reject invalid code range */ + } else { + if (c < 0xF0) { /* Three-byte sequence (0x800-0xFFFF) */ + f_read(fp, s, 2, &rc); + if (rc != 2) break; + c = c << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F); + if (c < 0x800) c = '?'; /* Reject invalid code range */ + } else { /* Reject four-byte sequence */ + c = '?'; + } + } + } +#elif _STRF_ENCODE == 2 /* Read a character in UTF-16BE */ + f_read(fp, s, 2, &rc); + if (rc != 2) break; + c = s[1] + (s[0] << 8); +#elif _STRF_ENCODE == 1 /* Read a character in UTF-16LE */ + f_read(fp, s, 2, &rc); + if (rc != 2) break; + c = s[0] + (s[1] << 8); +#else /* Read a character in ANSI/OEM */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = s[0]; + if (IsDBCS1(c)) { + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = (c << 8) + s[0]; + } + c = ff_convert(c, 1); /* OEM -> Unicode */ + if (!c) c = '?'; +#endif +#else /* Read a character without conversion */ + f_read(fp, s, 1, &rc); + if (rc != 1) break; + c = s[0]; +#endif + if (_USE_STRFUNC == 2 && c == '\r') continue; /* Strip '\r' */ + *p++ = c; + n++; + if (c == '\n') break; /* Break on EOL */ + } + *p = 0; + return n ? buff : 0; /* When no data read (eof or error), return with error. */ +} + + + + +#if !_FS_READONLY +#include +/*-----------------------------------------------------------------------*/ +/* Put a character to the file */ +/*-----------------------------------------------------------------------*/ + +typedef struct { + FIL *fp; /* Ptr to the writing file */ + int idx, nchr; /* Write index of buf[] (-1:error), number of chars written */ + BYTE buf[64]; /* Write buffer */ +} putbuff; + + +static +void putc_bfd ( /* Buffered write with code conversion */ + putbuff* pb, + TCHAR c +) +{ + UINT bw; + int i; + + + if (_USE_STRFUNC == 2 && c == '\n') { /* LF -> CRLF conversion */ + putc_bfd(pb, '\r'); + } + + i = pb->idx; /* Write index of pb->buf[] */ + if (i < 0) return; + +#if _LFN_UNICODE +#if _STRF_ENCODE == 3 /* Write a character in UTF-8 */ + if (c < 0x80) { /* 7-bit */ + pb->buf[i++] = (BYTE)c; + } else { + if (c < 0x800) { /* 11-bit */ + pb->buf[i++] = (BYTE)(0xC0 | c >> 6); + } else { /* 16-bit */ + pb->buf[i++] = (BYTE)(0xE0 | c >> 12); + pb->buf[i++] = (BYTE)(0x80 | (c >> 6 & 0x3F)); + } + pb->buf[i++] = (BYTE)(0x80 | (c & 0x3F)); + } +#elif _STRF_ENCODE == 2 /* Write a character in UTF-16BE */ + pb->buf[i++] = (BYTE)(c >> 8); + pb->buf[i++] = (BYTE)c; +#elif _STRF_ENCODE == 1 /* Write a character in UTF-16LE */ + pb->buf[i++] = (BYTE)c; + pb->buf[i++] = (BYTE)(c >> 8); +#else /* Write a character in ANSI/OEM */ + c = ff_convert(c, 0); /* Unicode -> OEM */ + if (!c) c = '?'; + if (c >= 0x100) + pb->buf[i++] = (BYTE)(c >> 8); + pb->buf[i++] = (BYTE)c; +#endif +#else /* Write a character without conversion */ + pb->buf[i++] = (BYTE)c; +#endif + + if (i >= (int)(sizeof pb->buf) - 3) { /* Write buffered characters to the file */ + f_write(pb->fp, pb->buf, (UINT)i, &bw); + i = (bw == (UINT)i) ? 0 : -1; + } + pb->idx = i; + pb->nchr++; +} + + +static +int putc_flush ( /* Flush left characters in the buffer */ + putbuff* pb +) +{ + UINT nw; + + if ( pb->idx >= 0 /* Flush buffered characters to the file */ + && f_write(pb->fp, pb->buf, (UINT)pb->idx, &nw) == FR_OK + && (UINT)pb->idx == nw) return pb->nchr; + return EOF; +} + + +static +void putc_init ( /* Initialize write buffer */ + putbuff* pb, + FIL* fp +) +{ + pb->fp = fp; + pb->nchr = pb->idx = 0; +} + + + +int f_putc ( + TCHAR c, /* A character to be output */ + FIL* fp /* Pointer to the file object */ +) +{ + putbuff pb; + + + putc_init(&pb, fp); + putc_bfd(&pb, c); /* Put the character */ + return putc_flush(&pb); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a string to the file */ +/*-----------------------------------------------------------------------*/ + +int f_puts ( + const TCHAR* str, /* Pointer to the string to be output */ + FIL* fp /* Pointer to the file object */ +) +{ + putbuff pb; + + + putc_init(&pb, fp); + while (*str) putc_bfd(&pb, *str++); /* Put the string */ + return putc_flush(&pb); +} + + + + +/*-----------------------------------------------------------------------*/ +/* Put a formatted string to the file */ +/*-----------------------------------------------------------------------*/ + +int f_printf ( + FIL* fp, /* Pointer to the file object */ + const TCHAR* fmt, /* Pointer to the format string */ + ... /* Optional arguments... */ +) +{ + va_list arp; + putbuff pb; + BYTE f, r; + UINT i, j, w; + DWORD v; + TCHAR c, d, str[32], *p; + + + putc_init(&pb, fp); + + va_start(arp, fmt); + + for (;;) { + c = *fmt++; + if (c == 0) break; /* End of string */ + if (c != '%') { /* Non escape character */ + putc_bfd(&pb, c); + continue; + } + w = f = 0; + c = *fmt++; + if (c == '0') { /* Flag: '0' padding */ + f = 1; c = *fmt++; + } else { + if (c == '-') { /* Flag: left justified */ + f = 2; c = *fmt++; + } + } + while (IsDigit(c)) { /* Precision */ + w = w * 10 + c - '0'; + c = *fmt++; + } + if (c == 'l' || c == 'L') { /* Prefix: Size is long int */ + f |= 4; c = *fmt++; + } + if (!c) break; + d = c; + if (IsLower(d)) d -= 0x20; + switch (d) { /* Type is... */ + case 'S' : /* String */ + p = va_arg(arp, TCHAR*); + for (j = 0; p[j]; j++) ; + if (!(f & 2)) { + while (j++ < w) putc_bfd(&pb, ' '); + } + while (*p) putc_bfd(&pb, *p++); + while (j++ < w) putc_bfd(&pb, ' '); + continue; + + case 'C' : /* Character */ + putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; + + case 'B' : /* Binary */ + r = 2; break; + + case 'O' : /* Octal */ + r = 8; break; + + case 'D' : /* Signed decimal */ + case 'U' : /* Unsigned decimal */ + r = 10; break; + + case 'X' : /* Hexdecimal */ + r = 16; break; + + default: /* Unknown type (pass-through) */ + putc_bfd(&pb, c); continue; + } + + /* Get an argument and put it in numeral */ + v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int)); + if (d == 'D' && (v & 0x80000000)) { + v = 0 - v; + f |= 8; + } + i = 0; + do { + d = (TCHAR)(v % r); v /= r; + if (d > 9) d += (c == 'x') ? 0x27 : 0x07; + str[i++] = d + '0'; + } while (v && i < sizeof str / sizeof str[0]); + if (f & 8) str[i++] = '-'; + j = i; d = (f & 1) ? '0' : ' '; + while (!(f & 2) && j++ < w) putc_bfd(&pb, d); + do { + putc_bfd(&pb, str[--i]); + } while (i); + while (j++ < w) putc_bfd(&pb, d); + } + + va_end(arp); + + return putc_flush(&pb); +} + +#endif /* !_FS_READONLY */ +#endif /* _USE_STRFUNC */ diff --git a/src/port_stm32f7/common/fatfs/ff.h b/src/port_stm32f7/common/fatfs/ff.h new file mode 100644 index 00000000..b14c3ce1 --- /dev/null +++ b/src/port_stm32f7/common/fatfs/ff.h @@ -0,0 +1,361 @@ +/*----------------------------------------------------------------------------/ +/ FatFs - Generic FAT file system module R0.12c / +/-----------------------------------------------------------------------------/ +/ +/ Copyright (C) 2017, ChaN, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: + +/ 1. Redistributions of source code must retain the above copyright notice, +/ this condition and the following disclaimer. +/ +/ This software is provided by the copyright holder and contributors "AS IS" +/ and any warranties related to this software are DISCLAIMED. +/ The copyright owner or contributors be NOT LIABLE for any damages caused +/ by use of this software. +/----------------------------------------------------------------------------*/ + + +#ifndef _FATFS +#define _FATFS 68300 /* Revision ID */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "integer.h" /* Basic integer types */ +#include "ffconf.h" /* FatFs configuration options */ + +#if _FATFS != _FFCONF +#error Wrong configuration file (ffconf.h). +#endif + + + +/* Definitions of volume management */ + +#if _MULTI_PARTITION /* Multiple partition configuration */ +typedef struct { + BYTE pd; /* Physical drive number */ + BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ +} PARTITION; +extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ +#endif + + + +/* Type of path name strings on FatFs API */ + +#if _LFN_UNICODE /* Unicode (UTF-16) string */ +#if _USE_LFN == 0 +#error _LFN_UNICODE must be 0 at non-LFN cfg. +#endif +#ifndef _INC_TCHAR +typedef WCHAR TCHAR; +#define _T(x) L ## x +#define _TEXT(x) L ## x +#endif +#else /* ANSI/OEM string */ +#ifndef _INC_TCHAR +typedef char TCHAR; +#define _T(x) x +#define _TEXT(x) x +#endif +#endif + + + +/* Type of file size variables */ + +#if _FS_EXFAT +#if _USE_LFN == 0 +#error LFN must be enabled when enable exFAT +#endif +typedef QWORD FSIZE_t; +#else +typedef DWORD FSIZE_t; +#endif + + + +/* File system object structure (FATFS) */ + +typedef struct { + BYTE fs_type; /* File system type (0:N/A) */ + BYTE drv; /* Physical drive number */ + BYTE n_fats; /* Number of FATs (1 or 2) */ + BYTE wflag; /* win[] flag (b0:dirty) */ + BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ + WORD id; /* File system mount ID */ + WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ + WORD csize; /* Cluster size [sectors] */ +#if _MAX_SS != _MIN_SS + WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ +#endif +#if _USE_LFN != 0 + WCHAR* lfnbuf; /* LFN working buffer */ +#endif +#if _FS_EXFAT + BYTE* dirbuf; /* Directory entry block scratchpad buffer */ +#endif +#if _FS_REENTRANT + _SYNC_t sobj; /* Identifier of sync object */ +#endif +#if !_FS_READONLY + DWORD last_clst; /* Last allocated cluster */ + DWORD free_clst; /* Number of free clusters */ +#endif +#if _FS_RPATH != 0 + DWORD cdir; /* Current directory start cluster (0:root) */ +#if _FS_EXFAT + DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ + DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ + DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ +#endif +#endif + DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ + DWORD fsize; /* Size of an FAT [sectors] */ + DWORD volbase; /* Volume base sector */ + DWORD fatbase; /* FAT base sector */ + DWORD dirbase; /* Root directory base sector/cluster */ + DWORD database; /* Data base sector */ + DWORD winsect; /* Current sector appearing in the win[] */ + BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ +} FATFS; + + + +/* Object ID and allocation information (_FDID) */ + +typedef struct { + FATFS* fs; /* Pointer to the owner file system object */ + WORD id; /* Owner file system mount ID */ + BYTE attr; /* Object attribute */ + BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:flagmented in this session, b2:sub-directory stretched) */ + DWORD sclust; /* Object start cluster (0:no cluster or root directory) */ + FSIZE_t objsize; /* Object size (valid when sclust != 0) */ +#if _FS_EXFAT + DWORD n_cont; /* Size of first fragment, clusters - 1 (valid when stat == 3) */ + DWORD n_frag; /* Size of last fragment needs to be written (valid when not zero) */ + DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ + DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ + DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0 and non-directory object) */ +#endif +#if _FS_LOCK != 0 + UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ +#endif +} _FDID; + + + +/* File object structure (FIL) */ + +typedef struct { + _FDID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ + BYTE flag; /* File status flags */ + BYTE err; /* Abort flag (error code) */ + FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ + DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ + DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ +#if !_FS_READONLY + DWORD dir_sect; /* Sector number containing the directory entry */ + BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ +#endif +#if _USE_FASTSEEK + DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ +#endif +#if !_FS_TINY + BYTE buf[_MAX_SS]; /* File private data read/write window */ +#endif +} FIL; + + + +/* Directory object structure (DIR) */ + +typedef struct { + _FDID obj; /* Object identifier */ + DWORD dptr; /* Current read/write offset */ + DWORD clust; /* Current cluster */ + DWORD sect; /* Current sector (0:Read operation has terminated) */ + BYTE* dir; /* Pointer to the directory item in the win[] */ + BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ +#if _USE_LFN != 0 + DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ +#endif +#if _USE_FIND + const TCHAR* pat; /* Pointer to the name matching pattern */ +#endif +} DIR; + + + +/* File information structure (FILINFO) */ + +typedef struct { + FSIZE_t fsize; /* File size */ + WORD fdate; /* Modified date */ + WORD ftime; /* Modified time */ + BYTE fattrib; /* File attribute */ +#if _USE_LFN != 0 + TCHAR altname[13]; /* Alternative file name */ + TCHAR fname[_MAX_LFN + 1]; /* Primary file name */ +#else + TCHAR fname[13]; /* File name */ +#endif +} FILINFO; + + + +/* File function return code (FRESULT) */ + +typedef enum { + FR_OK = 0, /* (0) Succeeded */ + FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ + FR_INT_ERR, /* (2) Assertion failed */ + FR_NOT_READY, /* (3) The physical drive cannot work */ + FR_NO_FILE, /* (4) Could not find the file */ + FR_NO_PATH, /* (5) Could not find the path */ + FR_INVALID_NAME, /* (6) The path name format is invalid */ + FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ + FR_EXIST, /* (8) Access denied due to prohibited access */ + FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ + FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ + FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ + FR_NOT_ENABLED, /* (12) The volume has no work area */ + FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ + FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ + FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ + FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ + FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ + FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */ + FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ +} FRESULT; + + + +/*--------------------------------------------------------------*/ +/* FatFs module application interface */ + +FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ +FRESULT f_close (FIL* fp); /* Close an open file object */ +FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ +FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ +FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ +FRESULT f_truncate (FIL* fp); /* Truncate the file */ +FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ +FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ +FRESULT f_closedir (DIR* dp); /* Close an open directory */ +FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ +FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ +FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ +FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ +FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ +FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ +FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ +FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ +FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ +FRESULT f_chdir (const TCHAR* path); /* Change current directory */ +FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ +FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ +FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ +FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ +FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ +FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ +FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */ +FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ +FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ +FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */ +int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ +int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ +int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ +TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ + +#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) +#define f_error(fp) ((fp)->err) +#define f_tell(fp) ((fp)->fptr) +#define f_size(fp) ((fp)->obj.objsize) +#define f_rewind(fp) f_lseek((fp), 0) +#define f_rewinddir(dp) f_readdir((dp), 0) +#define f_rmdir(path) f_unlink(path) + +#ifndef EOF +#define EOF (-1) +#endif + + + + +/*--------------------------------------------------------------*/ +/* Additional user defined functions */ + +/* RTC function */ +#if !_FS_READONLY && !_FS_NORTC +DWORD get_fattime (void); +#endif + +/* Unicode support functions */ +#if _USE_LFN != 0 /* Unicode - OEM code conversion */ +WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ +WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ +#if _USE_LFN == 3 /* Memory functions */ +void* ff_memalloc (UINT msize); /* Allocate memory block */ +void ff_memfree (void* mblock); /* Free memory block */ +#endif +#endif + +/* Sync functions */ +#if _FS_REENTRANT +int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */ +int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ +void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */ +int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ +#endif + + + + +/*--------------------------------------------------------------*/ +/* Flags and offset address */ + + +/* File access mode and open method flags (3rd argument of f_open) */ +#define FA_READ 0x01 +#define FA_WRITE 0x02 +#define FA_OPEN_EXISTING 0x00 +#define FA_CREATE_NEW 0x04 +#define FA_CREATE_ALWAYS 0x08 +#define FA_OPEN_ALWAYS 0x10 +#define FA_OPEN_APPEND 0x30 + +/* Fast seek controls (2nd argument of f_lseek) */ +#define CREATE_LINKMAP ((FSIZE_t)0 - 1) + +/* Format options (2nd argument of f_mkfs) */ +#define FM_FAT 0x01 +#define FM_FAT32 0x02 +#define FM_EXFAT 0x04 +#define FM_ANY 0x07 +#define FM_SFD 0x08 + +/* Filesystem type (FATFS.fs_type) */ +#define FS_FAT12 1 +#define FS_FAT16 2 +#define FS_FAT32 3 +#define FS_EXFAT 4 + +/* File attribute bits for directory entry (FILINFO.fattrib) */ +#define AM_RDO 0x01 /* Read only */ +#define AM_HID 0x02 /* Hidden */ +#define AM_SYS 0x04 /* System */ +#define AM_DIR 0x10 /* Directory */ +#define AM_ARC 0x20 /* Archive */ + + +#ifdef __cplusplus +} +#endif + +#endif /* _FATFS */ diff --git a/src/port_stm32f7/common/fatfs/ff_gen_drv.c b/src/port_stm32f7/common/fatfs/ff_gen_drv.c new file mode 100644 index 00000000..ccd595bb --- /dev/null +++ b/src/port_stm32f7/common/fatfs/ff_gen_drv.c @@ -0,0 +1,122 @@ +/** + ****************************************************************************** + * @file ff_gen_drv.c + * @author MCD Application Team + * @brief FatFs generic low level driver. + ***************************************************************************** + * @attention + * + * Copyright (c) 2017 STMicroelectronics. All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** +**/ +/* Includes ------------------------------------------------------------------*/ +#include "ff_gen_drv.h" + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +Disk_drvTypeDef disk = {{0},{0},{0},0}; + +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ + +/** + * @brief Links a compatible diskio driver/lun id and increments the number of active + * linked drivers. + * @note The number of linked drivers (volumes) is up to 10 due to FatFs limits. + * @param drv: pointer to the disk IO Driver structure + * @param path: pointer to the logical drive path + * @param lun : only used for USB Key Disk to add multi-lun management + else the parameter must be equal to 0 + * @retval Returns 0 in case of success, otherwise 1. + */ +uint8_t FATFS_LinkDriverEx(const Diskio_drvTypeDef *drv, char *path, uint8_t lun) +{ + uint8_t ret = 1; + uint8_t DiskNum = 0; + + if(disk.nbr < _VOLUMES) + { + disk.is_initialized[disk.nbr] = 0; + disk.drv[disk.nbr] = drv; + disk.lun[disk.nbr] = lun; + DiskNum = disk.nbr++; + path[0] = DiskNum + '0'; + path[1] = ':'; + path[2] = '/'; + path[3] = 0; + ret = 0; + } + + return ret; +} + +/** + * @brief Links a compatible diskio driver and increments the number of active + * linked drivers. + * @note The number of linked drivers (volumes) is up to 10 due to FatFs limits + * @param drv: pointer to the disk IO Driver structure + * @param path: pointer to the logical drive path + * @retval Returns 0 in case of success, otherwise 1. + */ +uint8_t FATFS_LinkDriver(const Diskio_drvTypeDef *drv, char *path) +{ + return FATFS_LinkDriverEx(drv, path, 0); +} + +/** + * @brief Unlinks a diskio driver and decrements the number of active linked + * drivers. + * @param path: pointer to the logical drive path + * @param lun : not used + * @retval Returns 0 in case of success, otherwise 1. + */ +uint8_t FATFS_UnLinkDriverEx(char *path, uint8_t lun) +{ + uint8_t DiskNum = 0; + uint8_t ret = 1; + + if(disk.nbr >= 1) + { + DiskNum = path[0] - '0'; + if(disk.drv[DiskNum] != 0) + { + disk.drv[DiskNum] = 0; + disk.lun[DiskNum] = 0; + disk.nbr--; + ret = 0; + } + } + + return ret; +} + +/** + * @brief Unlinks a diskio driver and decrements the number of active linked + * drivers. + * @param path: pointer to the logical drive path + * @retval Returns 0 in case of success, otherwise 1. + */ +uint8_t FATFS_UnLinkDriver(char *path) +{ + return FATFS_UnLinkDriverEx(path, 0); +} + +/** + * @brief Gets number of linked drivers to the FatFs module. + * @param None + * @retval Number of attached drivers. + */ +uint8_t FATFS_GetAttachedDriversNbr(void) +{ + return disk.nbr; +} + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/port_stm32f7/common/fatfs/ff_gen_drv.h b/src/port_stm32f7/common/fatfs/ff_gen_drv.h new file mode 100644 index 00000000..5172e0de --- /dev/null +++ b/src/port_stm32f7/common/fatfs/ff_gen_drv.h @@ -0,0 +1,80 @@ +/** + ****************************************************************************** + * @file ff_gen_drv.h + * @author MCD Application Team + * @brief Header for ff_gen_drv.c module. + ***************************************************************************** + * @attention + * + * Copyright (c) 2017 STMicroelectronics. All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** +**/ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __FF_GEN_DRV_H +#define __FF_GEN_DRV_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "diskio.h" +#include "ff.h" +#include "stdint.h" + + +/* Exported types ------------------------------------------------------------*/ + +/** + * @brief Disk IO Driver structure definition + */ +typedef struct +{ + DSTATUS (*disk_initialize) (BYTE); /*!< Initialize Disk Drive */ + DSTATUS (*disk_status) (BYTE); /*!< Get Disk Status */ + DRESULT (*disk_read) (BYTE, BYTE*, DWORD, UINT); /*!< Read Sector(s) */ +#if _USE_WRITE == 1 + DRESULT (*disk_write) (BYTE, const BYTE*, DWORD, UINT); /*!< Write Sector(s) when _USE_WRITE = 0 */ +#endif /* _USE_WRITE == 1 */ +#if _USE_IOCTL == 1 + DRESULT (*disk_ioctl) (BYTE, BYTE, void*); /*!< I/O control operation when _USE_IOCTL = 1 */ +#endif /* _USE_IOCTL == 1 */ + +}Diskio_drvTypeDef; + +/** + * @brief Global Disk IO Drivers structure definition + */ +typedef struct +{ + uint8_t is_initialized[_VOLUMES]; + const Diskio_drvTypeDef *drv[_VOLUMES]; + uint8_t lun[_VOLUMES]; + volatile uint8_t nbr; + +}Disk_drvTypeDef; + +/* Exported constants --------------------------------------------------------*/ +/* Exported macro ------------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ +uint8_t FATFS_LinkDriver(const Diskio_drvTypeDef *drv, char *path); +uint8_t FATFS_UnLinkDriver(char *path); +uint8_t FATFS_LinkDriverEx(const Diskio_drvTypeDef *drv, char *path, BYTE lun); +uint8_t FATFS_UnLinkDriverEx(char *path, BYTE lun); +uint8_t FATFS_GetAttachedDriversNbr(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __FF_GEN_DRV_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/src/port_stm32f7/common/fatfs/ffconf.h b/src/port_stm32f7/common/fatfs/ffconf.h new file mode 100644 index 00000000..6a7390f7 --- /dev/null +++ b/src/port_stm32f7/common/fatfs/ffconf.h @@ -0,0 +1,341 @@ +/*----------------------------------------------------------------------------/ +/ FatFs - Generic FAT file system module R0.12c / +/-----------------------------------------------------------------------------/ +/ +/ Copyright (C) 2017, ChaN, all right reserved. +/ Portions Copyright (C) STMicroelectronics, all right reserved. +/ +/ FatFs module is an open source software. Redistribution and use of FatFs in +/ source and binary forms, with or without modification, are permitted provided +/ that the following condition is met: + +/ 1. Redistributions of source code must retain the above copyright notice, +/ this condition and the following disclaimer. +/ +/ This software is provided by the copyright holder and contributors "AS IS" +/ and any warranties related to this software are DISCLAIMED. +/ The copyright owner or contributors be NOT LIABLE for any damages caused +/ by use of this software. +/----------------------------------------------------------------------------*/ + + +/*---------------------------------------------------------------------------/ +/ FatFs - FAT file system module configuration file +/---------------------------------------------------------------------------*/ + +#define _FFCONF 68300 /* Revision ID */ + +/*---------------------------------------------------------------------------/ +/ Function Configurations +/---------------------------------------------------------------------------*/ + +#define _FS_READONLY 0 +/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) +/ Read-only configuration removes writing API functions, f_write(), f_sync(), +/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() +/ and optional writing functions as well. */ + + +#define _FS_MINIMIZE 0 +/* This option defines minimization level to remove some basic API functions. +/ +/ 0: All basic functions are enabled. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() +/ are removed. +/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. +/ 3: f_lseek() function is removed in addition to 2. */ + + +#define _USE_STRFUNC 0 +/* This option switches string functions, f_gets(), f_putc(), f_puts() and +/ f_printf(). +/ +/ 0: Disable string functions. +/ 1: Enable without LF-CRLF conversion. +/ 2: Enable with LF-CRLF conversion. */ + + +#define _USE_FIND 0 +/* This option switches filtered directory read functions, f_findfirst() and +/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ + + +#define _USE_MKFS 1 +/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ + + +#define _USE_FASTSEEK 1 +/* This option switches fast seek function. (0:Disable or 1:Enable) */ + + +#define _USE_EXPAND 0 +/* This option switches f_expand function. (0:Disable or 1:Enable) */ + + +#define _USE_CHMOD 0 +/* This option switches attribute manipulation functions, f_chmod() and f_utime(). +/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */ + + +#define _USE_LABEL 0 +/* This option switches volume label functions, f_getlabel() and f_setlabel(). +/ (0:Disable or 1:Enable) */ + + +#define _USE_FORWARD 0 +/* This option switches f_forward() function. (0:Disable or 1:Enable) */ + + +/*---------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/---------------------------------------------------------------------------*/ + +#define _CODE_PAGE 437 +/* This option specifies the OEM code page to be used on the target system. +/ Incorrect setting of the code page can cause a file open failure. +/ +/ 1 - ASCII (No extended character. Non-LFN cfg. only) +/ 437 - U.S. +/ 720 - Arabic +/ 737 - Greek +/ 771 - KBL +/ 775 - Baltic +/ 850 - Latin 1 +/ 852 - Latin 2 +/ 855 - Cyrillic +/ 857 - Turkish +/ 860 - Portuguese +/ 861 - Icelandic +/ 862 - Hebrew +/ 863 - Canadian French +/ 864 - Arabic +/ 865 - Nordic +/ 866 - Russian +/ 869 - Greek 2 +/ 932 - Japanese (DBCS) +/ 936 - Simplified Chinese (DBCS) +/ 949 - Korean (DBCS) +/ 950 - Traditional Chinese (DBCS) +*/ + + +#define _USE_LFN 1 +#define _MAX_LFN 255 +/* The _USE_LFN switches the support of long file name (LFN). +/ +/ 0: Disable support of LFN. _MAX_LFN has no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added +/ to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and +/ additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255. +/ It should be set 255 to support full featured LFN operations. +/ When use stack for the working buffer, take care on stack overflow. When use heap +/ memory for the working buffer, memory management functions, ff_memalloc() and +/ ff_memfree(), must be added to the project. */ + + +#define _LFN_UNICODE 0 +/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16) +/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1. +/ This option also affects behavior of string I/O functions. */ + + +#define _STRF_ENCODE 3 +/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to +/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). +/ +/ 0: ANSI/OEM +/ 1: UTF-16LE +/ 2: UTF-16BE +/ 3: UTF-8 +/ +/ This option has no effect when _LFN_UNICODE == 0. */ + + +#define _FS_RPATH 1 +/* This option configures support of relative path. +/ +/ 0: Disable relative path and remove related functions. +/ 1: Enable relative path. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() function is available in addition to 1. +*/ + + +/*---------------------------------------------------------------------------/ +/ Drive/Volume Configurations +/---------------------------------------------------------------------------*/ + +#define _VOLUMES 2 +/* Number of volumes (logical drives) to be used. */ + + +#define _STR_VOLUME_ID 0 +#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" +/* _STR_VOLUME_ID switches string support of volume ID. +/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive +/ number in the path name. _VOLUME_STRS defines the drive ID strings for each +/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for +/ the drive ID strings are: A-Z and 0-9. */ + + +#define _MULTI_PARTITION 0 +/* This option switches support of multi-partition on a physical drive. +/ By default (0), each logical drive number is bound to the same physical drive +/ number and only an FAT volume found on the physical drive will be mounted. +/ When multi-partition is enabled (1), each logical drive number can be bound to +/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() +/ funciton will be available. */ + + +#define _MIN_SS 512 +#define _MAX_SS 512 +/* These options configure the range of sector size to be supported. (512, 1024, +/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and +/ harddisk. But a larger value may be required for on-board flash memory and some +/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured +/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the +/ disk_ioctl() function. */ + + +#define _USE_TRIM 0 +/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable) +/ To enable Trim function, also CTRL_TRIM command should be implemented to the +/ disk_ioctl() function. */ + + +#define _FS_NOFSINFO 0 +/* If you need to know correct free space on the FAT32 volume, set bit 0 of this +/ option, and f_getfree() function at first time after volume mount will force +/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. +/ +/ bit0=0: Use free cluster count in the FSINFO if available. +/ bit0=1: Do not trust free cluster count in the FSINFO. +/ bit1=0: Use last allocated cluster number in the FSINFO if available. +/ bit1=1: Do not trust last allocated cluster number in the FSINFO. +*/ + + + +/*---------------------------------------------------------------------------/ +/ System Configurations +/---------------------------------------------------------------------------*/ + +#define _FS_TINY 0 +/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) +/ At the tiny configuration, size of file object (FIL) is reduced _MAX_SS bytes. +/ Instead of private sector buffer eliminated from the file object, common sector +/ buffer in the file system object (FATFS) is used for the file data transfer. */ + + +#define _FS_EXFAT 1 +/* This option switches support of exFAT file system. (0:Disable or 1:Enable) +/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1) +/ Note that enabling exFAT discards C89 compatibility. */ + + +#define _FS_NORTC 1 +#define _NORTC_MON 1 +#define _NORTC_MDAY 1 +#define _NORTC_YEAR 2016 +/* The option _FS_NORTC switches timestamp functiton. If the system does not have +/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable +/ the timestamp function. All objects modified by FatFs will have a fixed timestamp +/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time. +/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be +/ added to the project to get current time form real-time clock. _NORTC_MON, +/ _NORTC_MDAY and _NORTC_YEAR have no effect. +/ These options have no effect at read-only configuration (_FS_READONLY = 1). */ + + +#define _FS_LOCK 2 +/* The option _FS_LOCK switches file lock function to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when _FS_READONLY +/ is 1. +/ +/ 0: Disable file lock function. To avoid volume corruption, application program +/ should avoid illegal open, remove and rename to the open objects. +/ >0: Enable file lock function. The value defines how many files/sub-directories +/ can be opened simultaneously under file lock control. Note that the file +/ lock control is independent of re-entrancy. */ + +#define _FS_REENTRANT 0 +#define _USE_MUTEX 0 +/* Use CMSIS-OS mutexes as _SYNC_t object instead of Semaphores */ + +#if _FS_REENTRANT + +#include "cmsis_os.h" +#define _FS_TIMEOUT 1000 + +#if _USE_MUTEX + +#if (osCMSIS < 0x20000U) +#define _SYNC_t osMutexId +#else +#define _SYNC_t osMutexId_t +#endif + +#else +#if (osCMSIS < 0x20000U) +#define _SYNC_t osSemaphoreId +#else +#define _SYNC_t osSemaphoreId_t +#endif + +#endif +#endif //_FS_REENTRANT +/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs +/ module itself. Note that regardless of this option, file access to different +/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() +/ and f_fdisk() function, are always not re-entrant. Only file/directory access +/ to the same volume is under control of this function. +/ +/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. +/ 1: Enable re-entrancy. Also user provided synchronization handlers, +/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() +/ function, must be added to the project. Samples are available in +/ option/syscall.c. +/ +/ The _FS_TIMEOUT defines timeout period in unit of time tick. +/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, +/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be +/ included somewhere in the scope of ff.h. */ + +/* #include // O/S definitions */ + +#if _USE_LFN == 3 + +#if !defined(ff_malloc) || !defined(ff_free) +#include +#endif + +#if !defined(ff_malloc) +#define ff_malloc malloc +#endif + +#if !defined(ff_free) +#define ff_free free +#endif + +/* by default the system malloc/free are used, but when the FreeRTOS is enabled +/ the macros pvPortMalloc()/vportFree() to be used thus uncomment the code below +/ +*/ +/* +#if !defined(ff_malloc) || !defined(ff_free) +#include "cmsis_os.h" +#endif + +#if !defined(ff_malloc) +#define ff_malloc pvPortMalloc +#endif + +#if !defined(ff_free) +#define ff_free vPortFree +#endif +*/ +#endif +/*--- End of configuration options ---*/ diff --git a/src/port_stm32f7/common/fatfs/integer.h b/src/port_stm32f7/common/fatfs/integer.h new file mode 100644 index 00000000..9ce7865b --- /dev/null +++ b/src/port_stm32f7/common/fatfs/integer.h @@ -0,0 +1,38 @@ +/*-------------------------------------------*/ +/* Integer type definitions for FatFs module */ +/*-------------------------------------------*/ + +#ifndef _FF_INTEGER +#define _FF_INTEGER + +#ifdef _WIN32 /* FatFs development platform */ + +#include +#include +typedef unsigned __int64 QWORD; + + +#else /* Embedded platform */ + +/* These types MUST be 16-bit or 32-bit */ +typedef int INT; +typedef unsigned int UINT; + +/* This type MUST be 8-bit */ +typedef unsigned char BYTE; + +/* These types MUST be 16-bit */ +typedef short SHORT; +typedef unsigned short WORD; +typedef unsigned short WCHAR; + +/* These types MUST be 32-bit */ +typedef long LONG; +typedef unsigned long DWORD; + +/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */ +typedef unsigned long long QWORD; + +#endif + +#endif diff --git a/src/port_stm32f7/common/fatfs/option/ccsbcs.c b/src/port_stm32f7/common/fatfs/option/ccsbcs.c new file mode 100644 index 00000000..e2762dc6 --- /dev/null +++ b/src/port_stm32f7/common/fatfs/option/ccsbcs.c @@ -0,0 +1,388 @@ +/*------------------------------------------------------------------------*/ +/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */ +/* (SBCS code pages) */ +/*------------------------------------------------------------------------*/ +/* 437 U.S. +/ 720 Arabic +/ 737 Greek +/ 771 KBL +/ 775 Baltic +/ 850 Latin 1 +/ 852 Latin 2 +/ 855 Cyrillic +/ 857 Turkish +/ 860 Portuguese +/ 861 Icelandic +/ 862 Hebrew +/ 863 Canadian French +/ 864 Arabic +/ 865 Nordic +/ 866 Russian +/ 869 Greek 2 +*/ + +#include "../ff.h" + + +#if _CODE_PAGE == 437 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 720 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */ + 0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A, + 0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 737 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */ + 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, + 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, + 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E, + 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 771 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 775 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */ + 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, + 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D, + 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019, + 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 850 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 852 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, + 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, + 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 855 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */ + 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, + 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, + 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580, + 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116, + 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 857 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 860 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2, + 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 861 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 862 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */ + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 863 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0, + 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192, + 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 864 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */ + 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518, + 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000, + 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5, + 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F, + 0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9, + 0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9, + 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1, + 0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000 +}; + +#elif _CODE_PAGE == 865 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */ + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 866 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 +}; + +#elif _CODE_PAGE == 869 +#define _TBLDEF 1 +static +const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */ + 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, + 0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF, + 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3, + 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580, + 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384, + 0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0 +}; + +#endif + + +#if !_TBLDEF || !_USE_LFN +#error This file is not needed at current configuration. Remove from the project. +#endif + + + + +WCHAR ff_convert ( /* Converted character, Returns zero on error */ + WCHAR chr, /* Character code to be converted */ + UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */ +) +{ + WCHAR c; + + + if (chr < 0x80) { /* ASCII */ + c = chr; + + } else { + if (dir) { /* OEM code to Unicode */ + c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80]; + + } else { /* Unicode to OEM code */ + for (c = 0; c < 0x80; c++) { + if (chr == Tbl[c]) break; + } + c = (c + 0x80) & 0xFF; + } + } + + return c; +} + + + +WCHAR ff_wtoupper ( /* Returns upper converted character */ + WCHAR chr /* Unicode character to be upper converted (BMP only) */ +) +{ + /* Compressed upper conversion table */ + static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */ + /* Basic Latin */ + 0x0061,0x031A, + /* Latin-1 Supplement */ + 0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178, + /* Latin Extended-A */ + 0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106, + /* Latin Extended-B */ + 0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA, + 0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128, + 0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A, + /* IPA Extensions */ + 0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7, + /* Greek, Coptic */ + 0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311, + 0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118, + 0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA, + /* Cyrillic */ + 0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144, + /* Armenian */ + 0x0561,0x0426, + + 0x0000 + }; + static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */ + /* Phonetic Extensions */ + 0x1D7D,0x0001,0x2C63, + /* Latin Extended Additional */ + 0x1E00,0x0196, 0x1EA0,0x015A, + /* Greek Extended */ + 0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606, + 0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608, + 0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB, + 0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC, + 0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC, + /* Letterlike Symbols */ + 0x214E,0x0001,0x2132, + /* Number forms */ + 0x2170,0x0210, 0x2184,0x0001,0x2183, + /* Enclosed Alphanumerics */ + 0x24D0,0x051A, 0x2C30,0x042F, + /* Latin Extended-C */ + 0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102, + /* Coptic */ + 0x2C80,0x0164, + /* Georgian Supplement */ + 0x2D00,0x0826, + /* Full-width */ + 0xFF41,0x031A, + + 0x0000 + }; + const WCHAR *p; + WCHAR bc, nc, cmd; + + + p = chr < 0x1000 ? cvt1 : cvt2; + for (;;) { + bc = *p++; /* Get block base */ + if (!bc || chr < bc) break; + nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */ + if (chr < bc + nc) { /* In the block? */ + switch (cmd) { + case 0: chr = p[chr - bc]; break; /* Table conversion */ + case 1: chr -= (chr - bc) & 1; break; /* Case pairs */ + case 2: chr -= 16; break; /* Shift -16 */ + case 3: chr -= 32; break; /* Shift -32 */ + case 4: chr -= 48; break; /* Shift -48 */ + case 5: chr -= 26; break; /* Shift -26 */ + case 6: chr += 8; break; /* Shift +8 */ + case 7: chr -= 80; break; /* Shift -80 */ + case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */ + } + break; + } + if (!cmd) p += nc; + } + + return chr; +} + diff --git a/src/port_stm32f7/common/fatfs/option/syscall.c b/src/port_stm32f7/common/fatfs/option/syscall.c new file mode 100644 index 00000000..cd6370dc --- /dev/null +++ b/src/port_stm32f7/common/fatfs/option/syscall.c @@ -0,0 +1,177 @@ +/*------------------------------------------------------------------------*/ +/* Sample code of OS dependent controls for FatFs */ +/* (C)ChaN, 2014 */ +/* Portions COPYRIGHT 2017 STMicroelectronics */ +/* Portions Copyright (C) 2014, ChaN, all right reserved */ +/*------------------------------------------------------------------------*/ + +/** + ****************************************************************************** + * @attention + * + * Copyright (c) 2017 STMicroelectronics. All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** +**/ + + + +#include "../ff.h" + + +#if _FS_REENTRANT +/*------------------------------------------------------------------------*/ +/* Create a Synchronization Object */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount() function to create a new +/ synchronization object, such as semaphore and mutex. When a 0 is returned, +/ the f_mount() function fails with FR_INT_ERR. +*/ + +int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ + BYTE vol, /* Corresponding volume (logical drive number) */ + _SYNC_t *sobj /* Pointer to return the created sync object */ +) +{ + + int ret; +#if _USE_MUTEX + +#if (osCMSIS < 0x20000U) + osMutexDef(MTX); + *sobj = osMutexCreate(osMutex(MTX)); +#else + *sobj = osMutexNew(NULL); +#endif + +#else + +#if (osCMSIS < 0x20000U) + osSemaphoreDef(SEM); + *sobj = osSemaphoreCreate(osSemaphore(SEM), 1); +#else + *sobj = osSemaphoreNew(1, 1, NULL); +#endif + +#endif + ret = (*sobj != NULL); + + return ret; +} + + + +/*------------------------------------------------------------------------*/ +/* Delete a Synchronization Object */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount() function to delete a synchronization +/ object that created with ff_cre_syncobj() function. When a 0 is returned, +/ the f_mount() function fails with FR_INT_ERR. +*/ + +int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to any error */ + _SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ +) +{ +#if _USE_MUTEX + osMutexDelete (sobj); +#else + osSemaphoreDelete (sobj); +#endif + return 1; +} + + + +/*------------------------------------------------------------------------*/ +/* Request Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on entering file functions to lock the volume. +/ When a 0 is returned, the file function fails with FR_TIMEOUT. +*/ + +int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ + _SYNC_t sobj /* Sync object to wait */ +) +{ + int ret = 0; +#if (osCMSIS < 0x20000U) + +#if _USE_MUTEX + if(osMutexWait(sobj, _FS_TIMEOUT) == osOK) +#else + if(osSemaphoreWait(sobj, _FS_TIMEOUT) == osOK) +#endif + +#else + +#if _USE_MUTEX + if(osMutexAcquire(sobj, _FS_TIMEOUT) == osOK) +#else + if(osSemaphoreAcquire(sobj, _FS_TIMEOUT) == osOK) +#endif + +#endif + { + ret = 1; + } + + return ret; +} + + + +/*------------------------------------------------------------------------*/ +/* Release Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on leaving file functions to unlock the volume. +*/ + +void ff_rel_grant ( + _SYNC_t sobj /* Sync object to be signaled */ +) +{ +#if _USE_MUTEX + osMutexRelease(sobj); +#else + osSemaphoreRelease(sobj); +#endif +} + +#endif + + + + +#if _USE_LFN == 3 /* LFN with a working buffer on the heap */ +/*------------------------------------------------------------------------*/ +/* Allocate a memory block */ +/*------------------------------------------------------------------------*/ +/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE. +*/ + +void* ff_memalloc ( /* Returns pointer to the allocated memory block */ + UINT msize /* Number of bytes to allocate */ +) +{ + return ff_malloc(msize); /* Allocate a new memory block with POSIX API */ +} + + +/*------------------------------------------------------------------------*/ +/* Free a memory block */ +/*------------------------------------------------------------------------*/ + +void ff_memfree ( + void* mblock /* Pointer to the memory block to free */ +) +{ + ff_free(mblock); /* Discard the memory block with POSIX API */ +} + +#endif diff --git a/src/port_stm32f7/common/fatfs/st_readme.txt b/src/port_stm32f7/common/fatfs/st_readme.txt new file mode 100644 index 00000000..a52e89a2 --- /dev/null +++ b/src/port_stm32f7/common/fatfs/st_readme.txt @@ -0,0 +1,221 @@ + @verbatim + ****************************************************************************** + * @file st_readme.txt + * @author MCD Application Team + * @brief This file lists the main modification done by STMicroelectronics on + * FatFs for integration with STM32Cube solution. + * For more details on FatFs implementation on STM32Cube, please refer + * to UM1721 "Developing Applications on STM32Cube with FatFs" + ****************************************************************************** + * @attention + * + * Copyright (c) 2017 STMicroelectronics. All rights reserved. + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + @endverbatim + +### V2.1.4/18-10-2019 ### +============================ ++ Fix wrong usage of the "memcpy" in the SD_Write() function + - drivers/sd_diskio_dma_template_bspv1.c + - drivers/sd_diskio_dma_template_bspv2.c + - drivers/sd_diskio_dma_rtos_template_bspv1.c + - drivers/sd_diskio_dma_rtos_template_bspv2.c + ++ correct the usage of the "_USE_MUTEX" config flag + - syscall.c + +### V2.1.3/26-07-2019 ### +============================ ++ add new BSPv2 templates: + - drivers/sd_diskio_dma_rtos_template_bspv2.c + - drivers/sd_diskio_dma_template_bspv2.c + - drivers/sd_diskio_template_bspv2.c + - drivers/sdram_diskio_template_bspv2.c + ++ rename old template to "xxxx_diskio_template_bspv1.c": + - drivers/sd_diskio_dma_rtos_template_bspv1.c + - drivers/sd_diskio_dma_template_bspv1.c + - drivers/sd_diskio_template_bspv1.c + - drivers/sdram_diskio_template_bspv1.c + ++ Add CMSIS-OSv2 support in templates, syscall.c and ff_conf_template.h + - syscall.c + - ff_conf_template.h + - drivers/sd_diskio_dma_rtos_template_bspv2.c + ++ support usage of "osMutex" alongside "osSemaphore" as _SYNC_t type in fatfs + - syscall.c + - ff_conf_template.h + + +### V2.1.2/29-03-2019 ### +============================ ++ add st_license.txt in the root directory ++ src/drivers/xxx_diskio_template.[c/h], src/ff_gen_drv.[c/h], src/option/syscall.c: update the license terms to BSD-3-Clause + +### V2.1.1/25-01-2019 ### +============================ ++ sd_diskio_dma_rtos_template.c + - Fix memory leak in the SD_Initialize() + - Disable the ENABLE_SD_DMA_CACHE_MAINTENANCE flag by default to fix a build error for CM4 + - include correct diskio header file + ++ sd_diskio_dma_template.c + - Correct the SD_read() function when enabling the ENABLE_SCRATCH_BUFFER flag + ++ sd_diskio_dma_rtos_template.c sd_diskio_dma_template.c + - fix potential overflow when using SysTick. + + +### V2.1.0/21-09-2018 ### +============================ ++ ff.c + - back-port a fix from 0.13, to correct an issue when using multi-threading + access in the same device due to a missing semaphore lock when calling + disk_status() API. + ++ sd_diskio_dma_rtos_template.c + - Add support to CMSIS-RTOS V2 API + ++ sd_diskio_dma_rtos_template.c sd_diskio_dma_template.c + - Add a compile flag "ENABLE_SCRATCH_BUFFER" to avoid misaligned access + caused buffer alignment constraint in some DMA versions. + - Add BSP_SD_ErrorCallback() and BSP_SD_AbortCallback() template functions. + +### V2.0.2/17-November-2017 ### +============================ ++ sdram_diskio_template.c sram_diskio_template.c + Fix wrong buffer size in the (SRAM/SDRAM)DISK_read(), (SRAM/SDRAM)DISK_write() + ++ sd_diskio_template.c + - define a generic 'SD_TIMEOUT' based on the BSP drivers defines. This fixes + a build issue when using this driver with the Adafruit shield. + ++ sd_diskio_dma_rtos_template.c + - add a check via osKernelRunning(), to avoid runtime errors due to + osMessageXXX calls that needs the "osKernelStart()" call done first. + ++ sd_diskio_dma_template.c, sd_diskio_dma_rtos_template.c + - fix wrong address alignment when calling SCB_InvalidateDCache_by_Addr() and + SCB_CleanDCache_by_Addr(), the address has to be 32-Byte and not + 32-bit aligned. + + - fix BSP_SD_ReadCpltCallback() and BSP_SD_WriteCpltCallback() prototypes by + adding 'void' as argument to avoid IAR compiler errors + + ++ sd_diskio_template.c sd_diskio_dma_template.c, sd_diskio_dma_rtos_template.c + - add the flag "DISABLE_SD_INIT" to give the user the choice to initialize the SD + either in the application or in the FatFs diskio driver. + ++ all xxx_diskio_template.c + - fix GET_BLOCK_SIZE ioctl call; the return value is in unit of sectors. + + +### V2.0.1/10-July-2017 ### +============================ ++ sd_diskio_dma_template.c, sd_diskio_dma_rtos_template.c + - add the flag "ENABLE_SD_DMA_CACHE_MAINTENANCE", to enable cache maintenance at each read write operation. + This is useful for STM32F7/STM32H7 based platforms when using a cachable memory region. + - add timeout checks in SD_Read() and SD_Write() to give the control back to the application to decide in case of errors. + ++ ff_gen_drv.c: fix a wrong check that causes an out of bound array access. + + +### V2.0.0/07-March-2017 ### +============================ + + Upgrade to use FatFS R0.12c. The R0.12c breaks the API compatibility with R0.11b. + - f_mkfs() API has a new signature. + - The _CODE_PAGE got new values. + - For more details check the files (doc/updates.txt) and the following urls: + http://elm-chan.org/fsw/ff/en/mkfs.html + http://elm-chan.org/fsw/ff/en/config.html + + + Add USB, RAMDISK and uSD template drivers under src/drivers. + - The diskio drivers aren't part of fatfs anymore, they are just templates instead. + - User has to copy the suitable template .c/.h file under the project, rename them by + removing the "_template" suffix then link them into the final application. + - The diskio driver .c/.h files have to be edited according to the used platform. + + + Define the macros "ff_malloc" and "ff_free" in the ff_conf_template.h and use + them in the syscall.c instead of direct calls to stdlib malloc and free functions. + + Define the "__weak" attribute in diskio.c for the GNU GCC compiler + + +### V1.4.0/09-September-2016 ### +================================ + + Upgrade to use FatFs R0.12b. + + ff_conf.h: remove the use of define "_USE_BUFF_WO_ALIGNMENT". + + +### V1.3.0/08-May-2015 ### +========================== + + Upgrade to use FatFs R0.11. + + Add new APIs FATFS_LinkDriverEx() and FATFS_UnLinkDriverEx() to manage USB Key Disk having + multi-lun capability. These APIs are equivalent to FATFS_LinkDriver() and FATFS_UnLinkDriver() + with "lun" parameter set to 0. + + ff_conf.h: add new define "_USE_BUFF_WO_ALIGNMENT". + This option is available only for usbh diskio interface and allow to disable + the management of the unaligned buffer. + When STM32 USB OTG HS or FS IP is used with internal DMA enabled, this define + must be set to 0 to align data into 32bits through an internal scratch buffer + before being processed by the DMA . Otherwise (DMA not used), this define must + be set to 1 to avoid Data alignment and improve the performance. + Please note that if _USE_BUFF_WO_ALIGNMENT is set to 1 and an unaligned 32bits + buffer is forwarded to the FatFs Write/Read functions, an error will be returned. + (0: default value or 1: unaligned buffer return an error). + + + + Important note: + For application code based on previous FatFs version; when moving to R0.11 + the changes that need to be done is to update ffconf.h file, taking + ffconf_template.h file as reference. + + +### V1.2.1/20-November-2014 ### +=============================== + + Disk I/O drivers; change count argument type from BYTE to UINT + + + Important note: + For application code based on previous FatFs version; when moving to R0.10b + the only change that need to be done is to update ffconf.h file, taking + ffconf_template.h file as reference. + + +### V1.2.0/04-November-2014 ### +=============================== + + Upgrade to use FatFs R0.10b. + + diskio.c: update disk_read() and disk_write() argument's type. + + + Important note: + For application code based on previous FatFs version; when moving to R0.10b + the only change that need to be done is to update ffconf.h file, taking + ffconf_template.h file as reference. + + +### V1.1.1/12-September-2014 ### +================================ + + ff_gen_drv.c: Update the Disk_drvTypeDef disk variable initialization to avoid + warnings detected with Atollic TrueSTUDIO Complier. + + +### V1.1.0/22-April-2014 ### +============================ + + Update sd_diskio to use SD BSP in polling mode instead of DMA mode (the scratch + buffer needed for DMA alignment is removed as well). + + diskio.c and ff_gen_drv.c/.h: update to prevent multiple initialization. + + +### V1.0.0/18-February-2014 ### +=============================== + + First R0.10 customized version for STM32Cube solution. + + + *

© COPYRIGHT STMicroelectronics

+ */ diff --git a/src/port_stm32f7/common/stm32f7xx_hal_timebase_tim.c b/src/port_stm32f7/common/stm32f7xx_hal_timebase_tim.c new file mode 100644 index 00000000..e9251eec --- /dev/null +++ b/src/port_stm32f7/common/stm32f7xx_hal_timebase_tim.c @@ -0,0 +1,181 @@ +/** + ****************************************************************************** + * @file stm32f7xx_hal_timebase_tim6.c + * @author MCD Application Team + * @brief HAL time base based on the hardware TIM6. + * + * This file overrides the native HAL time base functions (defined as weak) + * the TIM time base: + * + Initializes the TIM peripheral generate a Period elapsed Event each 1ms + * + HAL_IncTick is called inside HAL_TIM_PeriodElapsedCallback ie each 1ms + * + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2017 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/** @addtogroup STM32F7xx_HAL_Driver + * @{ + */ + +/** @addtogroup HAL_TimeBase + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +TIM_HandleTypeDef TimHandle; +/* Private function prototypes -----------------------------------------------*/ +void TIM6_DAC_IRQHandler(void); +/* Private functions ---------------------------------------------------------*/ + +/** + * @brief This function configures the TIM6 as a time base source. + * The time source is configured to have 1ms time base with a dedicated + * Tick interrupt priority. + * @note This function is called automatically at the beginning of program after + * reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig(). + * @param TickPriority Tick interrupt priority. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) +{ + RCC_ClkInitTypeDef clkconfig; + uint32_t uwTimclock, uwAPB1Prescaler = 0U; + uint32_t uwPrescalerValue = 0U; + uint32_t pFLatency; + HAL_StatusTypeDef status; + + /* Enable TIM6 clock */ + __HAL_RCC_TIM6_CLK_ENABLE(); + + /* Get clock configuration */ + HAL_RCC_GetClockConfig(&clkconfig, &pFLatency); + + /* Get APB1 prescaler */ + uwAPB1Prescaler = clkconfig.APB1CLKDivider; + + /* Compute TIM6 clock */ + if (uwAPB1Prescaler == RCC_HCLK_DIV1) + { + uwTimclock = HAL_RCC_GetPCLK1Freq(); + } + else + { + uwTimclock = 2 * HAL_RCC_GetPCLK1Freq(); + } + + /* Compute the prescaler value to have TIM6 counter clock equal to 1MHz */ + uwPrescalerValue = (uint32_t)((uwTimclock / 1000000U) - 1U); + + /* Initialize TIM6 */ + TimHandle.Instance = TIM6; + + /* Initialize TIMx peripheral as follow: + + Period = [(TIM6CLK/1000) - 1]. to have a (1/1000) s time base. + + Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock. + + ClockDivision = 0 + + Counter direction = Up + */ + TimHandle.Init.Period = (1000000U / 1000U) - 1U; + TimHandle.Init.Prescaler = uwPrescalerValue; + TimHandle.Init.ClockDivision = 0; + TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP; + TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + status = HAL_TIM_Base_Init(&TimHandle); + if (status == HAL_OK) + { + /* Start the TIM time Base generation in interrupt mode */ + status = HAL_TIM_Base_Start_IT(&TimHandle); + if (status == HAL_OK) + { + /* Enable the TIM6 global Interrupt */ + HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn); + + if (TickPriority < (1UL << __NVIC_PRIO_BITS)) + { + /* Enable the TIM6 global Interrupt */ + HAL_NVIC_SetPriority(TIM6_DAC_IRQn, TickPriority, 0); + uwTickPrio = TickPriority; + } + else + { + status = HAL_ERROR; + } + } + } + /* Return function status */ + return status; +} + +/** + * @brief Suspend Tick increment. + * @note Disable the tick increment by disabling TIM6 update interrupt. + * @retval None + */ +void HAL_SuspendTick(void) +{ + /* Disable TIM6 update Interrupt */ + __HAL_TIM_DISABLE_IT(&TimHandle, TIM_IT_UPDATE); +} + +/** + * @brief Resume Tick increment. + * @note Enable the tick increment by Enabling TIM6 update interrupt. + * @retval None + */ +void HAL_ResumeTick(void) +{ + /* Enable TIM6 Update interrupt */ + __HAL_TIM_ENABLE_IT(&TimHandle, TIM_IT_UPDATE); +} + +/** + * @brief Period elapsed callback in non blocking mode + * @note This function is called when TIM6 interrupt took place, inside + * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment + * a global variable "uwTick" used as application time base. + * @param htim TIM handle + * @retval None + */ +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) +{ + if (htim->Instance == TIM6) + { + HAL_IncTick(); + } +} + +/** + * @brief This function handles TIM interrupt request. + * @retval None + */ +void TIM6_DAC_IRQHandler(void) +{ + HAL_TIM_IRQHandler(&TimHandle); +} + + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/common/stm32f7xx_it.c b/src/port_stm32f7/common/stm32f7xx_it.c new file mode 100644 index 00000000..888a1e99 --- /dev/null +++ b/src/port_stm32f7/common/stm32f7xx_it.c @@ -0,0 +1,83 @@ +#include "main.h" + +/******************************************************************************/ +/* Cortex-M7 Processor Interruption and Exception Handlers */ +/******************************************************************************/ +/** + * @brief This function handles Non maskable interrupt. + */ +void NMI_Handler(void) +{ + while (1) + { + } +} + +/** + * @brief This function handles Hard fault interrupt. + */ +void HardFault_Handler(void) +{ + while (1) + { + } +} + +/** + * @brief This function handles Memory management fault. + */ +void MemManage_Handler(void) +{ + while (1) + { + } +} + +/** + * @brief This function handles Pre-fetch fault, memory access fault. + */ +void BusFault_Handler(void) +{ + while (1) + { + } +} + +/** + * @brief This function handles Undefined instruction or illegal state. + */ +void UsageFault_Handler(void) +{ + while (1) + { + } +} + +/** + * @brief This function handles System service call via SWI instruction. + */ +void SVC_Handler(void) +{ +} + +/** + * @brief This function handles Debug monitor. + */ +void DebugMon_Handler(void) +{ +} + +/** + * @brief This function handles Pendable request for system service. + */ +void PendSV_Handler(void) +{ +} + +/** + * @brief This function handles System tick timer. + */ +void SysTick_Handler(void) +{ +} + diff --git a/src/port_stm32f7/common/stm32fxx_hcd.c b/src/port_stm32f7/common/stm32fxx_hcd.c new file mode 100644 index 00000000..305e6dcd --- /dev/null +++ b/src/port_stm32f7/common/stm32fxx_hcd.c @@ -0,0 +1,330 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2018, hathach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" +#include "host/hcd.h" +#include "host/usbh.h" +#include "stm32f7xx_hal.h" +#if CFG_TUSB_MCU == OPT_MCU_STM32F7 +#include "device/dcd.h" + +#define NUM_PIPES 11 + +static HCD_HandleTypeDef hhcd; +static bool port_connected = 0; + +//For an IN, this field is the buffer size that the application has reserved for the transfer. The +//application is expected to program this field as an integer multiple of the maximum packet +//size for IN transactions (periodic and non-periodic). +//FIXME, how to make this more efficient? +static uint8_t _local_buffer[512]; +static uint32_t user_len; +static uint8_t *user_buff; + +static uint8_t _alloc_pipe() +{ + for (int i = 0; i < NUM_PIPES; i++) + { + if (hhcd.hc[i].max_packet == 0) + { + TU_LOG3("Allocated pipe %d\n\n\n", i); + return i; + } + } + TU_ASSERT(0); +} + +static uint8_t _find_pipe(uint8_t dev_addr, uint8_t ep_addr) +{ + //For control pipe we share the input and output pipe, so remove the direction bit. + if ((ep_addr & 0x7F) == 0) + { + ep_addr &= 0x7F; + } + for (int i = 0; i < NUM_PIPES; i++) + { + //STM HC pipes dont store the direction bit in the ep num filed, so re-add from ep_is_in it if not a control pipe so we can find it. + uint8_t hc_ep_addr = hhcd.hc[i].ep_num | ((hhcd.hc[i].ep_is_in && ep_addr != 0x00) ? 0x80 : 0x00); + if ((hhcd.hc[i].dev_addr == dev_addr) && (hc_ep_addr == ep_addr)) + { + TU_LOG2("Found pipe in slot %d for address %02x, ep_addr %02x\n", i, dev_addr, ep_addr); + return i; + } + } + TU_ASSERT(0); +} + +static void deferred_resetport(void *param) +{ + HAL_HCD_ResetPort(&hhcd); + //Device is reset, alert TinyUSB. + hcd_event_device_attach(0, false); +} + +void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd) +{ + //Need the reset port after connection to properly enable it. + //Create a event to be handled outside the ISR. + port_connected = true; + hcd_event_t event = + { + .event_id = USBH_EVENT_FUNC_CALL, + .func_call.func = deferred_resetport, + .func_call.param = NULL, + }; + hcd_event_handler(&event, true); +} + +void HAL_HCD_Disconnect_Callback(HCD_HandleTypeDef *hhcd) +{ + TU_LOG3("%s\n", __FUNCTION__); + port_connected = 0; + hcd_event_device_remove(0, true); +} + +void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum, HCD_URBStateTypeDef urb_state) +{ + HCD_HCTypeDef *hc = &hhcd->hc[chnum]; + uint8_t ep_addr = hc->ep_num | ((hc->ep_is_in) ? 0x80 : 0x00); + if (urb_state == URB_DONE) + { +/* + if (hc->ep_is_in && user_buff) + { + memcpy(user_buff, _local_buffer, user_len); + } +*/ + TU_LOG3("Transfer SUCCESS devadr%02x ep:%02x\n", hc->dev_addr, ep_addr); + hcd_event_xfer_complete(hc->dev_addr, ep_addr, hc->xfer_len, XFER_RESULT_SUCCESS, true); + } + else if (urb_state == URB_STALL) + { + TU_LOG1("Transfer ERROR: URB_STALL\n"); + hcd_event_xfer_complete(hc->dev_addr, ep_addr, hc->xfer_len, XFER_RESULT_STALLED, true); + } + else if (urb_state == URB_ERROR) + { + hcd_event_xfer_complete(hc->dev_addr, ep_addr, hc->xfer_len, XFER_RESULT_FAILED, true); + TU_LOG1("Transfer ERROR: URB_ERROR\n"); + } + else if (urb_state == URB_IDLE || urb_state == URB_IDLE) + { + //Resubmit URB (this happens sometimes) + HAL_HCD_HC_SubmitRequest(hhcd, chnum, hc->ep_is_in, hc->ep_type, 1, hc->xfer_buff, hc->xfer_len, 0); + } +} + +// HCD closes all opened endpoints belong to this device +void hcd_device_close(uint8_t rhport, uint8_t dev_addr) +{ + (void)rhport; + for (int i = 0; i < NUM_PIPES + 1; i++) + { + if (hhcd.hc[i].dev_addr == dev_addr && hhcd.hc[i].max_packet > 0) + { + TU_LOG3("Closing pipe %d\n", i); + HAL_HCD_HC_Halt(&hhcd, i); + tu_memclr(&hhcd.hc[i], sizeof(HCD_HCTypeDef)); + } + } +} + +// Enable USB interrupt +void hcd_int_enable(uint8_t rhport) +{ + (void)rhport; + __HAL_HCD_ENABLE(&hhcd); +} + +// Disable USB interrupt +void hcd_int_disable(uint8_t rhport) +{ + (void)rhport; + __HAL_HCD_DISABLE(&hhcd); +} + +// Get frame number (1ms) +uint32_t hcd_frame_number(uint8_t rhport) +{ + return HAL_HCD_GetCurrentFrame(&hhcd); +} + +// Get the current connect status of roothub port +bool hcd_port_connect_status(uint8_t rhport) +{ + (void)rhport; + return port_connected; +} + +// Reset USB bus on the port +void hcd_port_reset(uint8_t rhport) +{ + (void)rhport; + HAL_HCD_ResetPort(&hhcd); +} + +// Get port link speed +tusb_speed_t hcd_port_speed_get(uint8_t rhport) +{ + uint32_t speed = HAL_HCD_GetCurrentSpeed(&hhcd); + switch (speed) + { + case 0: + return TUSB_SPEED_HIGH; + case 1: + return TUSB_SPEED_FULL; + case 2: + return TUSB_SPEED_LOW; + default: + return TUSB_SPEED_FULL; + } + return TUSB_SPEED_INVALID; +} + +// Initialize controller to host mode +bool hcd_init(uint8_t rhport) +{ + (void)rhport; + HAL_StatusTypeDef res = HAL_ERROR; + hhcd.Instance = USB_OTG_FS; + hhcd.Init.Host_channels = NUM_PIPES; + hhcd.Init.dma_enable = 0; + hhcd.Init.low_power_enable = 0; + hhcd.Init.phy_itface = HCD_PHY_EMBEDDED; + hhcd.Init.Sof_enable = 0; + hhcd.Init.speed = HCD_SPEED_FULL; + hhcd.Init.vbus_sensing_enable = 0; + hhcd.Init.lpm_enable = 0; + res = HAL_HCD_Init(&hhcd); + if (res == HAL_OK) + { + res = HAL_HCD_Start(&hhcd); + } + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + return (res == HAL_OK); +} + +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *ep_desc) +{ + (void)rhport; + TU_LOG3("%s\n", __FUNCTION__); + int ret = HAL_OK; + + uint8_t ep_type = EP_TYPE_CTRL; + switch (ep_desc->bmAttributes.xfer) + { + case TUSB_XFER_CONTROL: + ep_type = EP_TYPE_CTRL; + break; + case TUSB_XFER_ISOCHRONOUS: + ep_type = EP_TYPE_ISOC; + break; + case TUSB_XFER_BULK: + ep_type = EP_TYPE_BULK; + break; + case TUSB_XFER_INTERRUPT: + ep_type = EP_TYPE_INTR; + break; + } + uint8_t ch_num = _alloc_pipe(); + tu_memclr(&hhcd.hc[ch_num], sizeof(HCD_HCTypeDef)); + TU_ASSERT(ep_desc->wMaxPacketSize > 0); //FIXME?, I relay on mps > 0 for pipe allocation + ret = HAL_HCD_HC_Init(&hhcd, ch_num, ep_desc->bEndpointAddress, dev_addr, HAL_HCD_GetCurrentSpeed(&hhcd), ep_type, ep_desc->wMaxPacketSize); + TU_LOG3("Opened pipe for devaddr:%d epaddr:%02x in slot %d\n", dev_addr, ep_desc->bEndpointAddress, ch_num); + return (ret == HAL_OK); +} + +bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) +{ + (void)rhport; + uint8_t ch_num = _find_pipe(dev_addr, 0x00); + + HAL_StatusTypeDef ret = HAL_HCD_HC_SubmitRequest(&hhcd, + ch_num, + 0, + EP_TYPE_CTRL, + 0, + (uint8_t *)setup_packet, + 8, + 0); + return ret == HAL_OK; +} + +bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen) +{ + (void)rhport; + + tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr); + uint8_t ch_num = _find_pipe(dev_addr, ep_addr); + TU_LOG2("hcd_edpt_xfer on pipe for devaddr:%d epaddr:%02x in slot %d, ep_type %d, ep_dir %d, len %d, togglein %d dir bool %d\n", + dev_addr, ep_addr, ch_num, hhcd.hc[ch_num].ep_type, ep_dir, buflen, hhcd.hc[ch_num].toggle_in, (ep_dir == TUSB_DIR_IN) ? 1 : 0); + + if (hhcd.hc[ch_num].urb_state == URB_NOTREADY || hhcd.hc[ch_num].urb_state == URB_NYET || (hhcd.hc[ch_num].state != HC_IDLE && hhcd.hc[ch_num].state != HC_XFRC)) + { + TU_LOG1("Error: Endpoint %02x is busy, urb: %02x hc: %02x\n", ep_addr, hhcd.hc[ch_num].urb_state, hhcd.hc[ch_num].state); + TU_ASSERT(0); + } + +/* + //FXIME. STM32F7 expects packets in multiples of maxpacket size. TinyUSB doesnt always do this so can overflow buffers + if ((ep_dir == TUSB_DIR_IN && (buflen % hhcd.hc[ch_num].max_packet != 0))) + { + TU_ASSERT(buflen < sizeof(_local_buffer)); + user_buff = buffer; + user_len = buflen; + buffer = _local_buffer; + } + else + { + user_buff = NULL; + } +*/ + + HAL_StatusTypeDef ret = HAL_HCD_HC_SubmitRequest(&hhcd, + ch_num, + (ep_dir == TUSB_DIR_IN) ? 1 : 0, + hhcd.hc[ch_num].ep_type, + 1, + buffer, + buflen, + 0); + + return (ret == HAL_OK); +} + +void hcd_int_handler(uint8_t rhport) +{ + HAL_HCD_IRQHandler(&hhcd); +} + +bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr) +{ + uint8_t ch_num = _find_pipe(dev_addr, ep_addr); + hhcd.hc[ch_num].urb_state = URB_IDLE; + return true; +} + +#endif diff --git a/src/port_stm32f7/common/system_stm32f7xx.c b/src/port_stm32f7/common/system_stm32f7xx.c new file mode 100644 index 00000000..c46602ef --- /dev/null +++ b/src/port_stm32f7/common/system_stm32f7xx.c @@ -0,0 +1,422 @@ +/** + ****************************************************************************** + * @file system_stm32f7xx.c + * @author MCD Application Team + * @brief CMSIS Cortex-M7 Device Peripheral Access Layer System Source File. + * + * This file provides two functions and one global variable to be called from + * user application: + * - SystemInit(): This function is called at startup just after reset and + * before branch to main program. This call is made inside + * the "startup_stm32f7xx.s" file. + * + * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used + * by the user application to setup the SysTick + * timer or configure other parameters. + * + * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must + * be called whenever the core clock is changed + * during program execution. + * + * + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2018 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32f7xx_system + * @{ + */ + +/** @addtogroup STM32F7xx_System_Private_Includes + * @{ + */ + +#include "stm32f7xx.h" + +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)25000000) /*!< Default value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @} + */ + +/** @addtogroup STM32F7xx_System_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32F7xx_System_Private_Defines + * @{ + */ + +/************************* Miscellaneous Configuration ************************/ +/*!< Uncomment the following line if you need to use external SDRAM mounted + on DK as data memory */ +/* #define DATA_IN_ExtSDRAM */ + +/*!< Uncomment the following line if you need to relocate your vector Table in + Internal SRAM. */ +/* #define VECT_TAB_SRAM */ +#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ +/******************************************************************************/ + +/** + * @} + */ + +/** @addtogroup STM32F7xx_System_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32F7xx_System_Private_Variables + * @{ + */ + + /* This variable is updated in three ways: + 1) by calling CMSIS function SystemCoreClockUpdate() + 2) by calling HAL API function HAL_RCC_GetHCLKFreq() + 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency + Note: If you use this function to configure the system clock; then there + is no need to call the 2 first functions listed above, since SystemCoreClock + variable is updated automatically. + */ + uint32_t SystemCoreClock = 16000000; + const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; + const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; + +/** + * @} + */ + +/** @addtogroup STM32F7xx_System_Private_FunctionPrototypes + * @{ + */ +#if defined (DATA_IN_ExtSDRAM) + static void SystemInit_ExtMemCtl(void); +#endif /* DATA_IN_ExtSDRAM */ + +/** + * @} + */ + +/** @addtogroup STM32F7xx_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system + * Initialize the Embedded Flash Interface, the PLL and update the + * SystemFrequency variable. + * @param None + * @retval None + */ +void SystemInit(void) +{ + /* FPU settings ------------------------------------------------------------*/ + #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) + SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */ + #endif + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set HSION bit */ + RCC->CR |= (uint32_t)0x00000001; + + /* Reset CFGR register */ + RCC->CFGR = 0x00000000; + + /* Reset HSEON, CSSON and PLLON bits */ + RCC->CR &= (uint32_t)0xFEF6FFFF; + + /* Reset PLLCFGR register */ + RCC->PLLCFGR = 0x24003010; + + /* Reset HSEBYP bit */ + RCC->CR &= (uint32_t)0xFFFBFFFF; + + /* Disable all interrupts */ + RCC->CIR = 0x00000000; + +#if defined (DATA_IN_ExtSDRAM) + SystemInit_ExtMemCtl(); +#endif /* DATA_IN_ExtSDRAM */ + + /* Configure the Vector Table location add offset address ------------------*/ +#ifdef VECT_TAB_SRAM + SCB->VTOR = SRAM1_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ +#else + SCB->VTOR = APPLICATION_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation to APPLICATION_ADDRESS in preprocessor defines */ +#endif +} + +/** + * @brief Update SystemCoreClock variable according to Clock Register Values. + * The SystemCoreClock variable contains the core clock (HCLK), it can + * be used by the user application to setup the SysTick timer or configure + * other parameters. + * + * @note Each time the core clock (HCLK) changes, this function must be called + * to update SystemCoreClock variable value. Otherwise, any configuration + * based on this variable will be incorrect. + * + * @note - The system frequency computed by this function is not the real + * frequency in the chip. It is calculated based on the predefined + * constant and the selected clock source: + * + * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*) + * + * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**) + * + * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) + * or HSI_VALUE(*) multiplied/divided by the PLL factors. + * + * (*) HSI_VALUE is a constant defined in stm32f7xx.h file (default value + * 16 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (**) HSE_VALUE is a constant defined in stm32f7xx.h file (default value + * 25 MHz), user has to ensure that HSE_VALUE is same as the real + * frequency of the crystal used. Otherwise, this function may + * have wrong result. + * + * - The result of this function could be not correct when using fractional + * value for HSE crystal. + * + * @param None + * @retval None + */ +void SystemCoreClockUpdate(void) +{ + uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2; + + /* Get SYSCLK source -------------------------------------------------------*/ + tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) + { + case 0x00: /* HSI used as system clock source */ + SystemCoreClock = HSI_VALUE; + break; + case 0x04: /* HSE used as system clock source */ + SystemCoreClock = HSE_VALUE; + break; + case 0x08: /* PLL used as system clock source */ + + /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N + SYSCLK = PLL_VCO / PLL_P + */ + pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22; + pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM; + + if (pllsource != 0) + { + /* HSE used as PLL clock source */ + pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); + } + else + { + /* HSI used as PLL clock source */ + pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6); + } + + pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2; + SystemCoreClock = pllvco/pllp; + break; + default: + SystemCoreClock = HSI_VALUE; + break; + } + /* Compute HCLK frequency --------------------------------------------------*/ + /* Get HCLK prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; + /* HCLK frequency */ + SystemCoreClock >>= tmp; +} + +#if defined (DATA_IN_ExtSDRAM) +/** + * @brief Setup the external memory controller. + * Called in startup_stm32f7xx.s before jump to main. + * This function configures the external memories (SDRAM) + * This SDRAM will be used as program data memory (including heap and stack). + * @param None + * @retval None + */ +void SystemInit_ExtMemCtl(void) +{ + register uint32_t tmpreg = 0, timeout = 0xFFFF; + register __IO uint32_t index; + + /* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG and GPIOH interface + clock */ + RCC->AHB1ENR |= 0x000000FC; + + /* Connect PCx pins to FMC Alternate function */ + GPIOC->AFR[0] = 0x0000C000; + GPIOC->AFR[1] = 0x00000000; + /* Configure PCx pins in Alternate function mode */ + GPIOC->MODER = 0x00000080; + /* Configure PCx pins speed to 50 MHz */ + GPIOC->OSPEEDR = 0x00000080; + /* Configure PCx pins Output type to push-pull */ + GPIOC->OTYPER = 0x00000000; + /* No pull-up, pull-down for PCx pins */ + GPIOC->PUPDR = 0x00000040; + + /* Connect PDx pins to FMC Alternate function */ + GPIOD->AFR[0] = 0x000000CC; + GPIOD->AFR[1] = 0xCC000CCC; + /* Configure PDx pins in Alternate function mode */ + GPIOD->MODER = 0xA02A000A; + /* Configure PDx pins speed to 50 MHz */ + GPIOD->OSPEEDR = 0xA02A000A; + /* Configure PDx pins Output type to push-pull */ + GPIOD->OTYPER = 0x00000000; + /* No pull-up, pull-down for PDx pins */ + GPIOD->PUPDR = 0x50150005; + + /* Connect PEx pins to FMC Alternate function */ + GPIOE->AFR[0] = 0xC00000CC; + GPIOE->AFR[1] = 0xCCCCCCCC; + /* Configure PEx pins in Alternate function mode */ + GPIOE->MODER = 0xAAAA800A; + /* Configure PEx pins speed to 50 MHz */ + GPIOE->OSPEEDR = 0xAAAA800A; + /* Configure PEx pins Output type to push-pull */ + GPIOE->OTYPER = 0x00000000; + /* No pull-up, pull-down for PEx pins */ + GPIOE->PUPDR = 0x55554005; + + /* Connect PFx pins to FMC Alternate function */ + GPIOF->AFR[0] = 0x00CCCCCC; + GPIOF->AFR[1] = 0xCCCCC000; + /* Configure PFx pins in Alternate function mode */ + GPIOF->MODER = 0xAA800AAA; + /* Configure PFx pins speed to 50 MHz */ + GPIOF->OSPEEDR = 0xAA800AAA; + /* Configure PFx pins Output type to push-pull */ + GPIOF->OTYPER = 0x00000000; + /* No pull-up, pull-down for PFx pins */ + GPIOF->PUPDR = 0x55400555; + + /* Connect PGx pins to FMC Alternate function */ + GPIOG->AFR[0] = 0x00CC00CC; + GPIOG->AFR[1] = 0xC000000C; + /* Configure PGx pins in Alternate function mode */ + GPIOG->MODER = 0x80020A0A; + /* Configure PGx pins speed to 50 MHz */ + GPIOG->OSPEEDR = 0x80020A0A; + /* Configure PGx pins Output type to push-pull */ + GPIOG->OTYPER = 0x00000000; + /* No pull-up, pull-down for PGx pins */ + GPIOG->PUPDR = 0x40010505; + + /* Connect PHx pins to FMC Alternate function */ + GPIOH->AFR[0] = 0x00C0C000; + GPIOH->AFR[1] = 0x00000000; + /* Configure PHx pins in Alternate function mode */ + GPIOH->MODER = 0x00000880; + /* Configure PHx pins speed to 50 MHz */ + GPIOH->OSPEEDR = 0x00000880; + /* Configure PHx pins Output type to push-pull */ + GPIOH->OTYPER = 0x00000000; + /* No pull-up, pull-down for PHx pins */ + GPIOH->PUPDR = 0x00000440; + + /* Enable the FMC interface clock */ + RCC->AHB3ENR |= 0x00000001; + + /* Configure and enable SDRAM bank1 */ + FMC_Bank5_6->SDCR[0] = 0x00001954; + FMC_Bank5_6->SDTR[0] = 0x01115351; + + /* SDRAM initialization sequence */ + /* Clock enable command */ + FMC_Bank5_6->SDCMR = 0x00000011; + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + while((tmpreg != 0) && (timeout-- > 0)) + { + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + } + + /* Delay */ + for (index = 0; index<1000; index++); + + /* PALL command */ + FMC_Bank5_6->SDCMR = 0x00000012; + timeout = 0xFFFF; + while((tmpreg != 0) && (timeout-- > 0)) + { + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + } + + /* Auto refresh command */ + FMC_Bank5_6->SDCMR = 0x000000F3; + timeout = 0xFFFF; + while((tmpreg != 0) && (timeout-- > 0)) + { + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + } + + /* MRD register program */ + FMC_Bank5_6->SDCMR = 0x00044014; + timeout = 0xFFFF; + while((tmpreg != 0) && (timeout-- > 0)) + { + tmpreg = FMC_Bank5_6->SDSR & 0x00000020; + } + + /* Set refresh count */ + tmpreg = FMC_Bank5_6->SDRTR; + FMC_Bank5_6->SDRTR = (tmpreg | (0x0000050C<<1)); + + /* Disable write protection */ + tmpreg = FMC_Bank5_6->SDCR[0]; + FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF); + + /* + * Disable the FMC bank1 (enabled after reset). + * This, prevents CPU speculation access on this bank which blocks the use of FMC during + * 24us. During this time the others FMC master (such as LTDC) cannot use it! + */ + FMC_Bank1->BTCR[0] = 0x000030d2; +} +#endif /* DATA_IN_ExtSDRAM */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/stm37f750-dk/STM32F750N8HX_EXTFLASH.ld b/src/port_stm32f7/stm37f750-dk/STM32F750N8HX_EXTFLASH.ld new file mode 100644 index 00000000..a6e2880d --- /dev/null +++ b/src/port_stm32f7/stm37f750-dk/STM32F750N8HX_EXTFLASH.ld @@ -0,0 +1,177 @@ +/* +***************************************************************************** +** + +** File : LinkerScript.ld +** +** Abstract : Linker script for STM32F750N8Hx Device with +** 16384KByte FLASH, 320KByte RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +** +** Distribution: The file is distributed as is, without any warranty +** of any kind. +** +** (c)Copyright Ac6. +** You may use this file as-is or modify it according to the needs of your +** project. Distribution of this file (unmodified or modified) is not +** permitted. Ac6 permit registered System Workbench for MCU users the +** rights to distribute the assembled, compiled & linked contents of this +** file as part of an application binary file, provided that it is built +** using the System Workbench for MCU toolchain. +** +***************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20050000; /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x400; /* required amount of heap */ +_Min_Stack_Size = 0x800; /* required amount of stack */ + +_EXT_RAM_SIZE = 7680K; + +/* Specify the memory areas */ +MEMORY +{ +FLASH (rx) : ORIGIN = 0x90000000, LENGTH = 16384K +RAM (xrw) : ORIGIN = 0x20000400, LENGTH = 319K +ERAM (xrw) : ORIGIN = 0xC0080000, LENGTH = _EXT_RAM_SIZE /* The first 0x80000 bytes are reserved for TFT framebuffer */ +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >RAM AT> FLASH + + .extram (NOLOAD) : { + . = ALIGN(4); + } > ERAM + + _extram_start = ADDR(.extram); + _extram_end = ADDR(.extram) + _EXT_RAM_SIZE; + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text.Reset_Handler) /* Reset handler needs to be in flash so its available to copy the other code to RAM */ + *(.text.code) /* Code that can remain in flash (not speed critical. init code etc) */ + *(.text.rodata) /* Read only data that can remain in flash to save RAM */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >RAM + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM AT> FLASH + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/src/port_stm32f7/stm37f750-dk/fileio_stm32.cpp b/src/port_stm32f7/stm37f750-dk/fileio_stm32.cpp new file mode 100644 index 00000000..a3e43a7b --- /dev/null +++ b/src/port_stm32f7/stm37f750-dk/fileio_stm32.cpp @@ -0,0 +1,138 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include "common.h" +#include "ff.h" +#include "ff_gen_drv.h" +#include "sd_diskio.h" + +static FATFS fs; +static char SDPath[4] = {0}; +extern const Diskio_drvTypeDef SD_Driver; + +bool fileio_dev_init() +{ + if (FATFS_LinkDriver(&SD_Driver, SDPath) != 0) + { + return false; + } + + int retries = 3; + + while (retries) + { + if (f_mount(&fs, (TCHAR const *)SDPath, 1) != FR_OK) + { + retries--; + if (retries == 0) + return false; + HAL_Delay(100); + } + else + { + break; + } + } + + return f_chdir((TCHAR const *)SDPath) == FR_OK; +} + +int fileio_dev_open_dir(const char *dir) +{ + DIR *dp = (DIR *)malloc(sizeof(DIR)); + if (dp == NULL) + { + return 0; + } + n64hal_disable_interrupts(); + FRESULT res = f_opendir(dp, (const TCHAR *)dir); + n64hal_enable_interrupts(); + + if (res != FR_OK) + { + free(dp); + return 0; + } + + return (uint32_t)dp; +} + +const char *fileio_dev_get_next_filename(int handle) +{ + static FILINFO fno; + FRESULT res; + DIR *dp = (DIR *)handle; + n64hal_disable_interrupts(); + res = f_readdir(dp, &fno); + n64hal_enable_interrupts(); + if (dp && res == FR_OK && fno.fname[0] != 0) + { + return fno.fname; + } + return NULL; +} + +void fileio_dev_close_dir(int handle) +{ + if (handle == 0) + { + return; + } + + DIR *dp = (DIR *)handle; + f_closedir(dp); + free(dp); +} + +int fileio_dev_read(char *filename, uint32_t file_offset, uint8_t *data, uint32_t len) +{ + FIL fil; + FRESULT res; + UINT br; + n64hal_disable_interrupts(); + res = f_open(&fil, filename, FA_READ); + if (res != FR_OK) + { + n64hal_enable_interrupts(); + return -1; + } + + f_lseek(&fil, file_offset); + res = f_read(&fil, data, len, &br); + if (res != FR_OK || br != len) + { + f_close(&fil); + n64hal_enable_interrupts(); + return -2; + } + + f_close(&fil); + n64hal_enable_interrupts(); + return 0; +} + +int fileio_dev_write(char *filename, uint8_t *data, uint32_t len) +{ + FIL fil; + FRESULT res; + UINT bw; + n64hal_disable_interrupts(); + res = f_open(&fil, filename, FA_WRITE | FA_CREATE_ALWAYS); + if (res != FR_OK) + { + n64hal_enable_interrupts(); + return -1; + } + + res = f_write(&fil, data, len, &bw); + if (res != FR_OK || bw != len) + { + f_close(&fil); + n64hal_enable_interrupts(); + return -2; + } + + f_close(&fil); + n64hal_enable_interrupts(); + return 0; +} diff --git a/src/port_stm32f7/stm37f750-dk/hal_stm32.cpp b/src/port_stm32f7/stm37f750-dk/hal_stm32.cpp new file mode 100644 index 00000000..1e6eb5ff --- /dev/null +++ b/src/port_stm32f7/stm37f750-dk/hal_stm32.cpp @@ -0,0 +1,509 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include "common.h" +#include "memory.h" +#include "fileio.h" +#include "memory.h" + +UART_HandleTypeDef huart6; +CRC_HandleTypeDef hcrc; + +static void SystemClock_Config(void); + +//usb64 passes a pin number to the backend (See port_conf.h). We need to convert this usb64 pin number to a +//port and device pin number. +typedef struct +{ + uint16_t pin; + GPIO_TypeDef *port; +} dev_gpio_t; + +static dev_gpio_t _dev_gpio[USB64_PIN_MAX]; +static dev_gpio_t *n64hal_pin_to_gpio(usb64_pin_t pin) +{ + if (pin == -1 || pin >= USB64_PIN_MAX) + { + return NULL; + } + return &_dev_gpio[pin]; +} + +//n64 controller interrupt handles +void (*n64_1)(void) = NULL; +void (*n64_2)(void) = NULL; +void (*n64_3)(void) = NULL; +void (*n64_4)(void) = NULL; + +void n64hal_system_init() +{ + SCB_EnableICache(); + SCB_EnableDCache(); + + HAL_Init(); + SystemClock_Config(); + + __disable_irq(); + //Move the interrupt vector table from Flash to RAM. Should have better interrupt perf and consistency + void *vtor = (void *)RAMDTCM_BASE; + memcpy(vtor, (void *)SCB->VTOR, 0x200); + SCB->VTOR = (uint32_t)vtor; + __enable_irq(); + + __HAL_RCC_CRC_CLK_ENABLE(); + hcrc.Instance = CRC; + hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE; + hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE; + hcrc.Init.GeneratingPolynomial = 0x85; + hcrc.Init.CRCLength = CRC_POLYLENGTH_8B; + hcrc.Init.InitValue = 0; + hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE; + hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE; + hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES; + HAL_CRC_Init(&hcrc); +} + +void n64hal_debug_init() +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + __HAL_RCC_USART6_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + GPIO_InitStruct.Pin = GPIO_PIN_7 | GPIO_PIN_6; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_USART6; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + huart6.Instance = USART6; + huart6.Init.BaudRate = 115200; + huart6.Init.WordLength = UART_WORDLENGTH_8B; + huart6.Init.StopBits = UART_STOPBITS_1; + huart6.Init.Parity = UART_PARITY_NONE; + huart6.Init.Mode = UART_MODE_TX_RX; + huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart6.Init.OverSampling = UART_OVERSAMPLING_16; + huart6.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; + huart6.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; + HAL_UART_Init(&huart6); +} + +void n64hal_gpio_init() +{ + dev_gpio_t *pin; + GPIO_InitTypeDef GPIO_InitStruct; + + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + + for (int i = 0; i < USB64_PIN_MAX; i++) + { + switch (i) + { + case N64_CONSOLE_SENSE_PIN: + _dev_gpio[i].pin = GPIO_PIN_4; //D3 + _dev_gpio[i].port = GPIOB; + break; + case N64_CONTROLLER_1_PIN: + _dev_gpio[i].pin = GPIO_PIN_6; //D2 + _dev_gpio[i].port = GPIOG; + break; + case N64_CONTROLLER_2_PIN: + _dev_gpio[i].pin = GPIO_PIN_7; //D4 + _dev_gpio[i].port = GPIOG; + break; + case N64_CONTROLLER_3_PIN: + _dev_gpio[i].pin = GPIO_PIN_3; //D7 + _dev_gpio[i].port = GPIOI; + break; + case N64_CONTROLLER_4_PIN: + _dev_gpio[i].pin = GPIO_PIN_2; //D8 + _dev_gpio[i].port = GPIOI; + break; + } + } + + pin = n64hal_pin_to_gpio(N64_CONSOLE_SENSE_PIN); + GPIO_InitStruct.Pin = pin->pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + HAL_GPIO_Init(pin->port, &GPIO_InitStruct); + + pin = n64hal_pin_to_gpio(N64_CONTROLLER_1_PIN); + HAL_GPIO_WritePin(pin->port, pin->pin, GPIO_PIN_RESET); + GPIO_InitStruct.Pin = pin->pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(pin->port, &GPIO_InitStruct); + + pin = n64hal_pin_to_gpio(N64_CONTROLLER_2_PIN); + HAL_GPIO_WritePin(pin->port, pin->pin, GPIO_PIN_RESET); + GPIO_InitStruct.Pin = pin->pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(pin->port, &GPIO_InitStruct); + + pin = n64hal_pin_to_gpio(N64_CONTROLLER_3_PIN); + HAL_GPIO_WritePin(pin->port, pin->pin, GPIO_PIN_RESET); + GPIO_InitStruct.Pin = pin->pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(pin->port, &GPIO_InitStruct); + + pin = n64hal_pin_to_gpio(N64_CONTROLLER_4_PIN); + HAL_GPIO_WritePin(pin->port, pin->pin, GPIO_PIN_RESET); + GPIO_InitStruct.Pin = pin->pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(pin->port, &GPIO_InitStruct); + + HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); + + HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(EXTI2_IRQn); + + HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(EXTI3_IRQn); + + NVIC_SetPriority(SysTick_IRQn, 15); +} + +void n64hal_debug_write(char c) +{ + HAL_UART_Transmit(&huart6, (uint8_t *)&c, 1, 5000); +} + +void n64hal_disable_interrupts() +{ + //Disable the controller input interrupts + HAL_NVIC_DisableIRQ(EXTI9_5_IRQn); + HAL_NVIC_DisableIRQ(EXTI2_IRQn); + HAL_NVIC_DisableIRQ(EXTI3_IRQn); +} + +void n64hal_enable_interrupts() +{ + //Disable the controller input interrupts + HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); + HAL_NVIC_EnableIRQ(EXTI2_IRQn); + HAL_NVIC_EnableIRQ(EXTI3_IRQn); +} + +void n64hal_attach_interrupt(usb64_pin_t pin, void (*handler)(void), int mode) +{ + (void)mode; //Should always be falling. Not used currently + switch (pin) + { + case N64_CONTROLLER_1_PIN: + n64_1 = handler; + break; + case N64_CONTROLLER_2_PIN: + n64_2 = handler; + break; + case N64_CONTROLLER_3_PIN: + n64_3 = handler; + break; + case N64_CONTROLLER_4_PIN: + n64_4 = handler; + break; + default: + break; //Not required + } +} + +void n64hal_detach_interrupt(usb64_pin_t pin) +{ + switch (pin) + { + case N64_CONTROLLER_1_PIN: + n64_1 = NULL; + break; + case N64_CONTROLLER_2_PIN: + n64_2 = NULL; + break; + case N64_CONTROLLER_3_PIN: + n64_3 = NULL; + break; + case N64_CONTROLLER_4_PIN: + n64_4 = NULL; + break; + default: + break; //Not required + } +} + +void n64hal_rtc_read(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s) +{ + //Not implemented +} + +void n64hal_rtc_write(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s) +{ + //Not implemented +} + +void n64hal_hs_tick_init() +{ + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->LAR = 0xC5ACCE55; + DWT->CYCCNT = 0; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; +} + +uint32_t n64hal_hs_tick_get_speed() +{ + return SystemCoreClock; +} + +uint32_t n64hal_hs_tick_get() +{ + return DWT->CYCCNT; +} + +uint32_t n64hal_millis() +{ + return HAL_GetTick(); +} + +void n64hal_input_swap(usb64_pin_t pin, uint8_t val) +{ + static uint16_t gpio_pin_offset[USB64_PIN_MAX]; + static uint8_t initialised[USB64_PIN_MAX] = {0}; + uint32_t mode = (val == N64_OUTPUT) ? GPIO_MODE_OUTPUT_PP : GPIO_MODE_INPUT; + + //Get the backend gpio from the pin number + dev_gpio_t *gpio = n64hal_pin_to_gpio(pin); + if (gpio == NULL) + { + return; + } + + //Get the pin offset of the gpio. ie. GPIO6 = 6. This only happens on the first call + //for efficiency + if (initialised[pin] == 0) + { + for (uint8_t i = 0; i < 16; i++) + { + if (gpio->pin & (1UL << i)) + gpio_pin_offset[pin] = i; + } + initialised[pin] = 1; + } + //Change the pin mode from input/outputpp + //When output, the line is driven low, when input is it floating (pulled up by resistor) + uint32_t temp = gpio->port->MODER; + uint32_t offset = gpio_pin_offset[pin]; + temp &= ~(GPIO_MODER_MODER0 << (offset * 2U)); + temp |= ((mode & GPIO_MODER_MODER0) << (offset * 2U)); + gpio->port->MODER = temp; +} + +uint8_t n64hal_input_read(usb64_pin_t pin) +{ + dev_gpio_t *gpio = n64hal_pin_to_gpio(pin); + if (gpio != NULL) + { + return HAL_GPIO_ReadPin(gpio->port, gpio->pin); + } + return 0; +} + +void n64hal_output_set(usb64_pin_t pin, uint8_t level) +{ + dev_gpio_t *gpio = n64hal_pin_to_gpio(pin); + if (gpio != NULL) + { + HAL_GPIO_WritePin(gpio->port, gpio->pin, (GPIO_PinState)level); + } + return; +} + +void n64hal_read_extram(void *rx_buff, void *src, uint32_t offset, uint32_t len) +{ + //External ram is just memory mapped. memcpy is fine + memcpy(rx_buff, (void *)((uintptr_t)src + offset), len); +} + +void n64hal_write_extram(void *tx_buff, void *dst, uint32_t offset, uint32_t len) +{ + //External ram is just memory mapped. memcpy is fine + memcpy((void *)((uintptr_t)dst + offset), tx_buff, len); + memory_mark_dirty(dst); +} + +void *n64hal_malloc(uint32_t len) +{ + return memory_dev_malloc(len); +} + +void n64hal_free(void *addr) +{ + memory_dev_free(addr); +} + +uint32_t n64hal_list_gb_roms(char **gb_list, uint32_t max) +{ + //Retrieve full directory list + char *file_list[256]; + uint32_t num_files = fileio_list_directory(file_list, 256); + + //Find only files with .gb or gbc extensions to populate rom list. + uint32_t rom_count = 0; + for (uint32_t i = 0; i < num_files; i++) + { + if (file_list[i] == NULL) + continue; + + if (strstr(file_list[i], ".GB\0") != NULL || strstr(file_list[i], ".GBC\0") != NULL || + strstr(file_list[i], ".gb\0") != NULL || strstr(file_list[i], ".gbc\0") != NULL) + { + if (rom_count < max) + { + gb_list[rom_count] = (char *)memory_dev_malloc(strlen(file_list[i]) + 1); + strcpy(gb_list[rom_count], file_list[i]); + rom_count++; + } + } + //Free file list as we go + memory_dev_free(file_list[i]); + } + return rom_count; +} + +void n64hal_read_storage(char *name, uint32_t file_offset, uint8_t *data, uint32_t len) +{ + fileio_read_from_file(name, file_offset, data, len); +} + +void Error_Handler(void) +{ + HAL_UART_Transmit(&huart6, (uint8_t *)"Error_Handler\n", 14, 5000); + __disable_irq(); + while (1) + { + } +} + +//STM32 specifics + +//STM32F7 has a powerful, configurable CRC unit. Use it instead of my software one which needs a fast CPU +extern "C" uint8_t n64_get_crc(uint8_t *data) +{ + return HAL_CRC_Calculate(&hcrc, (uint32_t *)data, 32); +} + +extern "C" void EXTI2_IRQHandler(void) +{ + if (n64_4) + { + n64_4(); + } + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2); +} + +extern "C" void EXTI3_IRQHandler(void) +{ + if (n64_3) + { + n64_3(); + } + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3); +} + +//This is a shared interrupt line for player 1 and 2. Need to determine which pin caused it and call appropriately +extern "C" void EXTI9_5_IRQHandler(void) +{ + if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_6) != RESET) + { + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6); + if (n64_1) + { + n64_1(); + } + } + if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_7) != RESET) + { + if (n64_2) + { + n64_2(); + } + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_7); + } +} + +void SystemClock_Config(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + + HAL_PWR_EnableBkUpAccess(); + + __HAL_RCC_PWR_CLK_ENABLE(); + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.LSIState = RCC_LSI_ON; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = 25; + RCC_OscInitStruct.PLL.PLLN = 400; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; + RCC_OscInitStruct.PLL.PLLQ = 9; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + Error_Handler(); + } + + if (HAL_PWREx_EnableOverDrive() != HAL_OK) + { + Error_Handler(); + } + + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6) != HAL_OK) + { + Error_Handler(); + } + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPDIFRX | RCC_PERIPHCLK_LTDC | + RCC_PERIPHCLK_RTC | RCC_PERIPHCLK_USART1 | + RCC_PERIPHCLK_USART6 | RCC_PERIPHCLK_SAI2 | + RCC_PERIPHCLK_I2C1 | RCC_PERIPHCLK_I2C3 | + RCC_PERIPHCLK_SDMMC1 | RCC_PERIPHCLK_CLK48; + PeriphClkInitStruct.PLLI2S.PLLI2SN = 100; + PeriphClkInitStruct.PLLI2S.PLLI2SP = RCC_PLLP_DIV2; + PeriphClkInitStruct.PLLI2S.PLLI2SR = 2; + PeriphClkInitStruct.PLLI2S.PLLI2SQ = 2; + PeriphClkInitStruct.PLLSAI.PLLSAIN = 192; + PeriphClkInitStruct.PLLSAI.PLLSAIR = 5; + PeriphClkInitStruct.PLLSAI.PLLSAIQ = 2; + PeriphClkInitStruct.PLLSAI.PLLSAIP = RCC_PLLSAIP_DIV4; + PeriphClkInitStruct.PLLI2SDivQ = 1; + PeriphClkInitStruct.PLLSAIDivQ = 1; + PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_4; + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; + PeriphClkInitStruct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLSAI; + PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2; + PeriphClkInitStruct.Usart6ClockSelection = RCC_USART6CLKSOURCE_PCLK2; + PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1; + PeriphClkInitStruct.I2c3ClockSelection = RCC_I2C3CLKSOURCE_PCLK1; + PeriphClkInitStruct.Clk48ClockSelection = RCC_CLK48SOURCE_PLLSAIP; + PeriphClkInitStruct.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_CLK48; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) + { + Error_Handler(); + } +} diff --git a/src/port_stm32f7/stm37f750-dk/main.h b/src/port_stm32f7/stm37f750-dk/main.h new file mode 100644 index 00000000..491b07cf --- /dev/null +++ b/src/port_stm32f7/stm37f750-dk/main.h @@ -0,0 +1,377 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.h + * @brief : Header for main.c file. + * This file contains the common defines of the application. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MAIN_H +#define __MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim); + +/* Exported functions prototypes ---------------------------------------------*/ +void Error_Handler(void); + +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +/* Private defines -----------------------------------------------------------*/ +#define LCD_B0_Pin GPIO_PIN_4 +#define LCD_B0_GPIO_Port GPIOE +#define OTG_HS_OverCurrent_Pin GPIO_PIN_3 +#define OTG_HS_OverCurrent_GPIO_Port GPIOE +#define QSPI_D2_Pin GPIO_PIN_2 +#define QSPI_D2_GPIO_Port GPIOE +#define RMII_TXD1_Pin GPIO_PIN_14 +#define RMII_TXD1_GPIO_Port GPIOG +#define FMC_NBL1_Pin GPIO_PIN_1 +#define FMC_NBL1_GPIO_Port GPIOE +#define FMC_NBL0_Pin GPIO_PIN_0 +#define FMC_NBL0_GPIO_Port GPIOE +#define ARDUINO_SCL_D15_Pin GPIO_PIN_8 +#define ARDUINO_SCL_D15_GPIO_Port GPIOB +#define ARDUINO_D3_Pin GPIO_PIN_4 +#define ARDUINO_D3_GPIO_Port GPIOB +#define SWO_Pin GPIO_PIN_3 +#define SWO_GPIO_Port GPIOB +#define SPDIF_RX0_Pin GPIO_PIN_7 +#define SPDIF_RX0_GPIO_Port GPIOD +#define SDMMC_CK_Pin GPIO_PIN_12 +#define SDMMC_CK_GPIO_Port GPIOC +#define ARDUINO_PWM_D9_Pin GPIO_PIN_15 +#define ARDUINO_PWM_D9_GPIO_Port GPIOA +#define SWCLK_Pin GPIO_PIN_14 +#define SWCLK_GPIO_Port GPIOA +#define SWDIO_Pin GPIO_PIN_13 +#define SWDIO_GPIO_Port GPIOA +#define DCMI_D6_Pin GPIO_PIN_5 +#define DCMI_D6_GPIO_Port GPIOE +#define DCMI_D7_Pin GPIO_PIN_6 +#define DCMI_D7_GPIO_Port GPIOE +#define RMII_TXD0_Pin GPIO_PIN_13 +#define RMII_TXD0_GPIO_Port GPIOG +#define ARDUINO_SDA_D14_Pin GPIO_PIN_9 +#define ARDUINO_SDA_D14_GPIO_Port GPIOB +#define VCP_RX_Pin GPIO_PIN_7 +#define VCP_RX_GPIO_Port GPIOB +#define QSPI_NCS_Pin GPIO_PIN_6 +#define QSPI_NCS_GPIO_Port GPIOB +#define FMC_SDNCAS_Pin GPIO_PIN_15 +#define FMC_SDNCAS_GPIO_Port GPIOG +#define RMII_TX_EN_Pin GPIO_PIN_11 +#define RMII_TX_EN_GPIO_Port GPIOG +#define LCD_B1_Pin GPIO_PIN_13 +#define LCD_B1_GPIO_Port GPIOJ +#define OTG_FS_VBUS_Pin GPIO_PIN_12 +#define OTG_FS_VBUS_GPIO_Port GPIOJ +#define FMC_D2_Pin GPIO_PIN_0 +#define FMC_D2_GPIO_Port GPIOD +#define SDMMC_D3_Pin GPIO_PIN_11 +#define SDMMC_D3_GPIO_Port GPIOC +#define SDMMC_D2_Pin GPIO_PIN_10 +#define SDMMC_D2_GPIO_Port GPIOC +#define OTG_FS_P_Pin GPIO_PIN_12 +#define OTG_FS_P_GPIO_Port GPIOA +#define NC1_Pin GPIO_PIN_8 +#define NC1_GPIO_Port GPIOI +#define SAI2_MCLKA_Pin GPIO_PIN_4 +#define SAI2_MCLKA_GPIO_Port GPIOI +#define LCD_DE_Pin GPIO_PIN_7 +#define LCD_DE_GPIO_Port GPIOK +#define LCD_B7_Pin GPIO_PIN_6 +#define LCD_B7_GPIO_Port GPIOK +#define LCD_B6_Pin GPIO_PIN_5 +#define LCD_B6_GPIO_Port GPIOK +#define LCD_B4_Pin GPIO_PIN_12 +#define LCD_B4_GPIO_Port GPIOG +#define SAI2_SDB_Pin GPIO_PIN_10 +#define SAI2_SDB_GPIO_Port GPIOG +#define LCD_B2_Pin GPIO_PIN_14 +#define LCD_B2_GPIO_Port GPIOJ +#define OTG_FS_PowerSwitchOn_Pin GPIO_PIN_5 +#define OTG_FS_PowerSwitchOn_GPIO_Port GPIOD +#define DCMI_D5_Pin GPIO_PIN_3 +#define DCMI_D5_GPIO_Port GPIOD +#define FMC_D3_Pin GPIO_PIN_1 +#define FMC_D3_GPIO_Port GPIOD +#define ARDUINO_D7_Pin GPIO_PIN_3 +#define ARDUINO_D7_GPIO_Port GPIOI +#define ARDUINO_D7_EXTI_IRQn EXTI3_IRQn +#define ARDUINO_D8_Pin GPIO_PIN_2 +#define ARDUINO_D8_GPIO_Port GPIOI +#define ARDUINO_D8_EXTI_IRQn EXTI2_IRQn +#define OTG_FS_N_Pin GPIO_PIN_11 +#define OTG_FS_N_GPIO_Port GPIOA +#define uSD_Detect_Pin GPIO_PIN_13 +#define uSD_Detect_GPIO_Port GPIOC +#define FMC_A0_Pin GPIO_PIN_0 +#define FMC_A0_GPIO_Port GPIOF +#define SAI2_SCKA_Pin GPIO_PIN_5 +#define SAI2_SCKA_GPIO_Port GPIOI +#define SAI2_FSA_Pin GPIO_PIN_7 +#define SAI2_FSA_GPIO_Port GPIOI +#define LCD_HSYNC_Pin GPIO_PIN_10 +#define LCD_HSYNC_GPIO_Port GPIOI +#define SAI2_SDA_Pin GPIO_PIN_6 +#define SAI2_SDA_GPIO_Port GPIOI +#define LCD_B5_Pin GPIO_PIN_4 +#define LCD_B5_GPIO_Port GPIOK +#define LCD_BL_CTRL_Pin GPIO_PIN_3 +#define LCD_BL_CTRL_GPIO_Port GPIOK +#define DCMI_VSYNC_Pin GPIO_PIN_9 +#define DCMI_VSYNC_GPIO_Port GPIOG +#define LCD_B3_Pin GPIO_PIN_15 +#define LCD_B3_GPIO_Port GPIOJ +#define OTG_FS_OverCurrent_Pin GPIO_PIN_4 +#define OTG_FS_OverCurrent_GPIO_Port GPIOD +#define SDMMC_CMD_Pin GPIO_PIN_2 +#define SDMMC_CMD_GPIO_Port GPIOD +#define TP3_Pin GPIO_PIN_15 +#define TP3_GPIO_Port GPIOH +#define ARDUINO_SCK_D13_Pin GPIO_PIN_1 +#define ARDUINO_SCK_D13_GPIO_Port GPIOI +#define OTG_FS_ID_Pin GPIO_PIN_10 +#define OTG_FS_ID_GPIO_Port GPIOA +#define RCC_OSC32_IN_Pin GPIO_PIN_14 +#define RCC_OSC32_IN_GPIO_Port GPIOC +#define FMC_A1_Pin GPIO_PIN_1 +#define FMC_A1_GPIO_Port GPIOF +#define LCD_DISP_Pin GPIO_PIN_12 +#define LCD_DISP_GPIO_Port GPIOI +#define LCD_VSYNC_Pin GPIO_PIN_9 +#define LCD_VSYNC_GPIO_Port GPIOI +#define DCMI_PWR_EN_Pin GPIO_PIN_13 +#define DCMI_PWR_EN_GPIO_Port GPIOH +#define DCMI_D4_Pin GPIO_PIN_14 +#define DCMI_D4_GPIO_Port GPIOH +#define ARDUINO_PWM_CS_D5_Pin GPIO_PIN_0 +#define ARDUINO_PWM_CS_D5_GPIO_Port GPIOI +#define VCP_TX_Pin GPIO_PIN_9 +#define VCP_TX_GPIO_Port GPIOA +#define RCC_OSC32_OUT_Pin GPIO_PIN_15 +#define RCC_OSC32_OUT_GPIO_Port GPIOC +#define LCD_G6_Pin GPIO_PIN_1 +#define LCD_G6_GPIO_Port GPIOK +#define LCD_G7_Pin GPIO_PIN_2 +#define LCD_G7_GPIO_Port GPIOK +#define ARDUINO_PWM_D10_Pin GPIO_PIN_8 +#define ARDUINO_PWM_D10_GPIO_Port GPIOA +#define OSC_25M_Pin GPIO_PIN_0 +#define OSC_25M_GPIO_Port GPIOH +#define FMC_A2_Pin GPIO_PIN_2 +#define FMC_A2_GPIO_Port GPIOF +#define LCD_INT_Pin GPIO_PIN_13 +#define LCD_INT_GPIO_Port GPIOI +#define LCD_R0_Pin GPIO_PIN_15 +#define LCD_R0_GPIO_Port GPIOI +#define LCD_G4_Pin GPIO_PIN_11 +#define LCD_G4_GPIO_Port GPIOJ +#define LCD_G5_Pin GPIO_PIN_0 +#define LCD_G5_GPIO_Port GPIOK +#define ARDUINO_RX_D0_Pin GPIO_PIN_7 +#define ARDUINO_RX_D0_GPIO_Port GPIOC +#define FMC_A3_Pin GPIO_PIN_3 +#define FMC_A3_GPIO_Port GPIOF +#define LCD_CLK_Pin GPIO_PIN_14 +#define LCD_CLK_GPIO_Port GPIOI +#define LCD_G1_Pin GPIO_PIN_8 +#define LCD_G1_GPIO_Port GPIOJ +#define LCD_G3_Pin GPIO_PIN_10 +#define LCD_G3_GPIO_Port GPIOJ +#define FMC_SDCLK_Pin GPIO_PIN_8 +#define FMC_SDCLK_GPIO_Port GPIOG +#define ARDUINO_TX_D1_Pin GPIO_PIN_6 +#define ARDUINO_TX_D1_GPIO_Port GPIOC +#define FMC_A4_Pin GPIO_PIN_4 +#define FMC_A4_GPIO_Port GPIOF +#define FMC_SDNME_Pin GPIO_PIN_5 +#define FMC_SDNME_GPIO_Port GPIOH +#define FMC_SDNE0_Pin GPIO_PIN_3 +#define FMC_SDNE0_GPIO_Port GPIOH +#define LCD_G0_Pin GPIO_PIN_7 +#define LCD_G0_GPIO_Port GPIOJ +#define LCD_G2_Pin GPIO_PIN_9 +#define LCD_G2_GPIO_Port GPIOJ +#define ARDUINO_D4_Pin GPIO_PIN_7 +#define ARDUINO_D4_GPIO_Port GPIOG +#define ARDUINO_D4_EXTI_IRQn EXTI9_5_IRQn +#define ARDUINO_D2_Pin GPIO_PIN_6 +#define ARDUINO_D2_GPIO_Port GPIOG +#define ARDUINO_D2_EXTI_IRQn EXTI9_5_IRQn +#define ARDUINO_A4_Pin GPIO_PIN_7 +#define ARDUINO_A4_GPIO_Port GPIOF +#define ARDUINO_A5_Pin GPIO_PIN_6 +#define ARDUINO_A5_GPIO_Port GPIOF +#define FMC_A5_Pin GPIO_PIN_5 +#define FMC_A5_GPIO_Port GPIOF +#define NC2_Pin GPIO_PIN_2 +#define NC2_GPIO_Port GPIOH +#define LCD_R7_Pin GPIO_PIN_6 +#define LCD_R7_GPIO_Port GPIOJ +#define FMC_D1_Pin GPIO_PIN_15 +#define FMC_D1_GPIO_Port GPIOD +#define FMC_D15_Pin GPIO_PIN_10 +#define FMC_D15_GPIO_Port GPIOD +#define ARDUINO_A1_Pin GPIO_PIN_10 +#define ARDUINO_A1_GPIO_Port GPIOF +#define ARDUINO_A2_Pin GPIO_PIN_9 +#define ARDUINO_A2_GPIO_Port GPIOF +#define ARDUINO_A3_Pin GPIO_PIN_8 +#define ARDUINO_A3_GPIO_Port GPIOF +#define FMC_SDCKE0_Pin GPIO_PIN_3 +#define FMC_SDCKE0_GPIO_Port GPIOC +#define FMC_D0_Pin GPIO_PIN_14 +#define FMC_D0_GPIO_Port GPIOD +#define FMC_D14_Pin GPIO_PIN_9 +#define FMC_D14_GPIO_Port GPIOD +#define FMC_D13_Pin GPIO_PIN_8 +#define FMC_D13_GPIO_Port GPIOD +#define RMII_MDC_Pin GPIO_PIN_1 +#define RMII_MDC_GPIO_Port GPIOC +#define FMC_A6_Pin GPIO_PIN_12 +#define FMC_A6_GPIO_Port GPIOF +#define FMC_A11_Pin GPIO_PIN_1 +#define FMC_A11_GPIO_Port GPIOG +#define FMC_A9_Pin GPIO_PIN_15 +#define FMC_A9_GPIO_Port GPIOF +#define LCD_R5_Pin GPIO_PIN_4 +#define LCD_R5_GPIO_Port GPIOJ +#define QSPI_D1_Pin GPIO_PIN_12 +#define QSPI_D1_GPIO_Port GPIOD +#define QSPI_D3_Pin GPIO_PIN_13 +#define QSPI_D3_GPIO_Port GPIOD +#define EXT_RST_Pin GPIO_PIN_3 +#define EXT_RST_GPIO_Port GPIOG +#define RMII_RXER_Pin GPIO_PIN_2 +#define RMII_RXER_GPIO_Port GPIOG +#define LCD_R6_Pin GPIO_PIN_5 +#define LCD_R6_GPIO_Port GPIOJ +#define DCMI_D3_Pin GPIO_PIN_12 +#define DCMI_D3_GPIO_Port GPIOH +#define RMII_REF_CLK_Pin GPIO_PIN_1 +#define RMII_REF_CLK_GPIO_Port GPIOA +#define ARDUINO_A0_Pin GPIO_PIN_0 +#define ARDUINO_A0_GPIO_Port GPIOA +#define DCMI_HSYNC_Pin GPIO_PIN_4 +#define DCMI_HSYNC_GPIO_Port GPIOA +#define RMII_RXD0_Pin GPIO_PIN_4 +#define RMII_RXD0_GPIO_Port GPIOC +#define FMC_A7_Pin GPIO_PIN_13 +#define FMC_A7_GPIO_Port GPIOF +#define FMC_A10_Pin GPIO_PIN_0 +#define FMC_A10_GPIO_Port GPIOG +#define LCD_R4_Pin GPIO_PIN_3 +#define LCD_R4_GPIO_Port GPIOJ +#define FMC_D5_Pin GPIO_PIN_8 +#define FMC_D5_GPIO_Port GPIOE +#define QSPI_D0_Pin GPIO_PIN_11 +#define QSPI_D0_GPIO_Port GPIOD +#define FMC_BA1_Pin GPIO_PIN_5 +#define FMC_BA1_GPIO_Port GPIOG +#define FMC_BA0_Pin GPIO_PIN_4 +#define FMC_BA0_GPIO_Port GPIOG +#define LCD_SCL_Pin GPIO_PIN_7 +#define LCD_SCL_GPIO_Port GPIOH +#define DCMI_D0_Pin GPIO_PIN_9 +#define DCMI_D0_GPIO_Port GPIOH +#define DCMI_D2_Pin GPIO_PIN_11 +#define DCMI_D2_GPIO_Port GPIOH +#define RMII_MDIO_Pin GPIO_PIN_2 +#define RMII_MDIO_GPIO_Port GPIOA +#define RMII_RXD1_Pin GPIO_PIN_5 +#define RMII_RXD1_GPIO_Port GPIOC +#define FMC_A8_Pin GPIO_PIN_14 +#define FMC_A8_GPIO_Port GPIOF +#define LCD_R3_Pin GPIO_PIN_2 +#define LCD_R3_GPIO_Port GPIOJ +#define FMC_SDNRAS_Pin GPIO_PIN_11 +#define FMC_SDNRAS_GPIO_Port GPIOF +#define FMC_D6_Pin GPIO_PIN_9 +#define FMC_D6_GPIO_Port GPIOE +#define FMC_D8_Pin GPIO_PIN_11 +#define FMC_D8_GPIO_Port GPIOE +#define FMC_D11_Pin GPIO_PIN_14 +#define FMC_D11_GPIO_Port GPIOE +#define ULPI_D3_Pin GPIO_PIN_10 +#define ULPI_D3_GPIO_Port GPIOB +#define ARDUINO_PWM_D6_Pin GPIO_PIN_6 +#define ARDUINO_PWM_D6_GPIO_Port GPIOH +#define LCD_SDA_Pin GPIO_PIN_8 +#define LCD_SDA_GPIO_Port GPIOH +#define DCMI_D1_Pin GPIO_PIN_10 +#define DCMI_D1_GPIO_Port GPIOH +#define RMII_CRS_DV_Pin GPIO_PIN_7 +#define RMII_CRS_DV_GPIO_Port GPIOA +#define LCD_R1_Pin GPIO_PIN_0 +#define LCD_R1_GPIO_Port GPIOJ +#define LCD_R2_Pin GPIO_PIN_1 +#define LCD_R2_GPIO_Port GPIOJ +#define FMC_D4_Pin GPIO_PIN_7 +#define FMC_D4_GPIO_Port GPIOE +#define FMC_D7_Pin GPIO_PIN_10 +#define FMC_D7_GPIO_Port GPIOE +#define FMC_D9_Pin GPIO_PIN_12 +#define FMC_D9_GPIO_Port GPIOE +#define FMC_D12_Pin GPIO_PIN_15 +#define FMC_D12_GPIO_Port GPIOE +#define FMC_D10_Pin GPIO_PIN_13 +#define FMC_D10_GPIO_Port GPIOE +#define ARDUINO_MISO_D12_Pin GPIO_PIN_14 +#define ARDUINO_MISO_D12_GPIO_Port GPIOB +#define ARDUINO_MOSI_PWM_D11_Pin GPIO_PIN_15 +#define ARDUINO_MOSI_PWM_D11_GPIO_Port GPIOB +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +#ifdef __cplusplus +} +#endif + +#endif /* __MAIN_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/stm37f750-dk/memory_stm32.cpp b/src/port_stm32f7/stm37f750-dk/memory_stm32.cpp new file mode 100644 index 00000000..71a58793 --- /dev/null +++ b/src/port_stm32f7/stm37f750-dk/memory_stm32.cpp @@ -0,0 +1,75 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include "common.h" +#include "tinyalloc.h" +#include "memory.h" + +//Pulled in from linker. +extern uint32_t _extram_start; +extern uint32_t _extram_end; + +static uint32_t extram_start = 0; +static uint32_t extram_end = 0; + +bool memory_dev_init() +{ + extram_start = (int)&_extram_start; + extram_end = (int)&_extram_end; + + //There's 8MB usable SDRAM on the f750-k board located from 0xC0000000 + //The first 512kBytes are reversed for the LCD. extram_start starts just after this (at 0xC0080000) + //I create a new heap at this location for allocating large files + extern SDRAM_HandleTypeDef sdramHandle; + if (sdramHandle.State != HAL_SDRAM_STATE_READY) + { + BSP_SDRAM_Init(); + } + + uint32_t extram_bytes = extram_end - extram_start; + ta_init((void *)(extram_start), //Base of heap + (void *)(extram_end), //End of heap + extram_bytes / 32768, //Number of memory chunks (32k/per chunk) + 16, //Smaller chunks than this won't split + 4); //32 word size alignment + + debug_print_memory("[MEMORY] External memory initialised\n"); + debug_print_memory("[MEMORY] Detected %ukB\n", extram_bytes / 1024); + debug_print_memory("[MEMORY] Heap start: %08x\n", (void *)(extram_start)); + debug_print_memory("[MEMORY] Heap end: %08x\n", (void *)(extram_end)); + debug_print_memory("[MEMORY] Number of memory chunks: %u\n", extram_bytes / 32768); + return true; +} + +void *memory_dev_malloc(uint32_t len) +{ + void *pt = ta_alloc(len); + if (pt == NULL) + { + debug_print_error("[MEMORY] ERROR, could not allocate memory\n"); + } + return pt; +} + +void memory_dev_free(void *add) +{ + if ((uint32_t)add >= extram_start) + { + ta_free(add); + } + else + { + free(add); + } +} + +/* + * Function: Detect the amount of external RAM installed. This prints it to the LCD and a number > 0 is required for TPAK + * emulation. If you device has loads of internal RAM suitable for TPAK emulation (>2MB or so) which you want to use, set this to a non-zero number. + * ---------------------------- + * Returns: How many MB of external RAM is installed. + */ +uint8_t memory_get_ext_ram_size() +{ + return (extram_end - extram_start) / 1024 / 1024; +} diff --git a/src/port_stm32f7/stm37f750-dk/port_conf.h b/src/port_stm32f7/stm37f750-dk/port_conf.h new file mode 100644 index 00000000..19778344 --- /dev/null +++ b/src/port_stm32f7/stm37f750-dk/port_conf.h @@ -0,0 +1,71 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT +#ifndef _USB64_CONF_h +#define _USB64_CONF_h + +//Specific headers for this port +#include +#include "stm32f7508_discovery_lcd.h" +#include "stm32f7508_discovery_sd.h" +#include "stm32f7508_discovery_sdram.h" +#include "main.h" + +/* PIN MAPPING - Teensy uses an Arduino Backend, we just assign the enum to the Arduino Pin number + USB64_PIN_MAX must be the largest pin number in the list add one*/ +typedef enum { + USER_LED_PIN = -1, + N64_FRAME_PIN = -1, + HW_RUMBLE = -1, + N64_CONSOLE_SENSE_PIN, + N64_CONTROLLER_1_PIN, + N64_CONTROLLER_2_PIN, + N64_CONTROLLER_3_PIN, + N64_CONTROLLER_4_PIN, +/* + N64_FRAME_PIN, + USER_LED_PIN, + HW_A, + HW_B, + HW_CU, + HW_CD, + HW_CL, + HW_CR, + HW_DU, + HW_DD, + HW_DL, + HW_DR, + HW_START, + HW_Z, + HW_R, + HW_L, + HW_RUMBLE, //Output, 1 when should be rumbling + HW_EN, //Active low, pulled high + HW_X, //Analog input, 0V to VCC. VCC/2 centre + HW_Y, //Analog input, 0V to VCC. VCC/2 centre + TFT_DC, + TFT_CS, + TFT_MOSI, + TFT_SCK, + TFT_MISO, + TFT_RST, +*/ + USB64_PIN_MAX, +} usb64_pin_t; + +/* TFT DISPLAY */ +#define ENABLE_TFT_DISPLAY 1 +#define TFT_WIDTH 480 +#define TFT_HEIGHT 272 +#define TFT_PIXEL_SIZE 4 +#define TFT_USE_FRAMEBUFFER 0 + +/* Define for variables to store in flash only */ +#ifndef PROGMEM +#define PROGMEM __attribute__((section(".text.rodata"))) +#endif +/* Define for function to store in flash only */ +#ifndef FLASHMEM +#define FLASHMEM __attribute__ ((section (".text.code"))) +#endif + +#endif diff --git a/src/port_stm32f7/stm37f750-dk/tft_stm32.cpp b/src/port_stm32f7/stm37f750-dk/tft_stm32.cpp new file mode 100644 index 00000000..9feca6e3 --- /dev/null +++ b/src/port_stm32f7/stm37f750-dk/tft_stm32.cpp @@ -0,0 +1,88 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include "common.h" +#include "tft.h" +#include "controller_icon.h" +#include "usb64_logo.h" +#include "GuiLite.h" + +#define TFT_FRAMEBUFFER_SIZE (TFT_WIDTH * TFT_HEIGHT * TFT_PIXEL_SIZE) +c_surface *psurface_guilite = NULL; +c_display *pdisplay_guilite = NULL; +#if TFT_USE_FRAMEBUFFER +static uint8_t *_framebuffer = (uint8_t *)(LCD_FB_START_ADDRESS); +#else +static uint8_t *_framebuffer = (uint8_t *)(LCD_FB_START_ADDRESS); +struct EXTERNAL_GFX_OP my_gfx_op; +#endif + +static void _tft_assert(const char *file, int line) +{ + debug_print_error("[TFT] Error: Assert in %s on line %d\n", file, line); + while (1) + ; +} + +static void _tft_log_out(const char *log) +{ + debug_print_status(log); +} + +#if TFT_USE_FRAMEBUFFER == 0 +static void _draw_pixel(int x, int y, unsigned int rgb) +{ + //Device specific pixel draw + BSP_LCD_DrawPixel(x, y, rgb); +} + +static void _fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) +{ + BSP_LCD_SetTextColor(rgb); + BSP_LCD_FillRect(x0, y0, x1 - x0, y1 - y0); + //Weird, but the above FillRect leaves before finshing properly. This fixes it? + BSP_LCD_FillRect(x0, y0, 1, 1); +} +#endif + +void tft_dev_draw(bool force) +{ + //Dont need to do anything. This TFT just updates from the SDRAM buffer automatically. +} + +extern "C" void BSP_LCD_ClockConfig(LTDC_HandleTypeDef *hltdc, void *Params) +{ + //Overrise the internal clock config as it messes with other clock divs and multipliers. + //Dont do anything. All clocks are setup properly at boot +} + +void tft_dev_init() +{ +#if TFT_USE_FRAMEBUFFER + static c_surface surface(TFT_WIDTH, TFT_HEIGHT, 2, Z_ORDER_LEVEL_0); + static c_display display(_framebuffer, TFT_WIDTH, TFT_HEIGHT, &surface); + psurface_guilite = &surface; + pdisplay_guilite = &display; +#else + static c_surface_no_fb surface(TFT_WIDTH, TFT_HEIGHT, 2, &my_gfx_op, Z_ORDER_LEVEL_0); + static c_display display(NULL, TFT_WIDTH, TFT_HEIGHT, &surface); + my_gfx_op.draw_pixel = _draw_pixel; + my_gfx_op.fill_rect = _fill_rect; +#endif + psurface_guilite = &surface; + pdisplay_guilite = &display; + register_debug_function(_tft_assert, _tft_log_out); +#if (ENABLE_TFT_DISPLAY >= 1) + BSP_LCD_Init(); + BSP_LCD_LayerDefaultInit(0, (uint32_t)_framebuffer); + BSP_LCD_SelectLayer(0); + BSP_LCD_SetBackColor(TFT_BG_COLOR); + BSP_LCD_Clear(TFT_BG_COLOR); + BSP_LCD_DisplayOn(); +#endif +} + +bool tft_dev_is_busy() +{ + return 0; +} diff --git a/src/port_stm32f7/stm37f750-dk/usbh_stm32.cpp b/src/port_stm32f7/stm37f750-dk/usbh_stm32.cpp new file mode 100644 index 00000000..89b47fe0 --- /dev/null +++ b/src/port_stm32f7/stm37f750-dk/usbh_stm32.cpp @@ -0,0 +1,44 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include "common.h" +#include "stm32f7xx_hal.h" +#include "tusb.h" + +HCD_HandleTypeDef hhcd_USB_OTG_FS; + +//Forward the OTG_FS interrupt to the tinyusb handler +extern "C" void hcd_int_handler(uint8_t rhport); +extern "C" void OTG_FS_IRQHandler(void) +{ + hcd_int_handler(0); +} + +void usbh_dev_init() +{ + //Enable clocks + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + GPIO_InitTypeDef GPIO_InitStruct; + + //Turn on 5V output + GPIO_InitStruct.Pin = OTG_FS_PowerSwitchOn_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(OTG_FS_PowerSwitchOn_GPIO_Port, &GPIO_InitStruct); + HAL_GPIO_WritePin(OTG_FS_PowerSwitchOn_GPIO_Port, OTG_FS_PowerSwitchOn_Pin, GPIO_PIN_RESET); + + //Setup USB data pins + GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); + HAL_NVIC_SetPriority(OTG_FS_IRQn, 6, 0); + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); +} From bffa184f50cad9f16f07e8da8d5e80e5053970e3 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Thu, 16 Dec 2021 18:58:12 +1030 Subject: [PATCH 080/121] usb64: Update platformio.ini --- platformio.ini | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/platformio.ini b/platformio.ini index c98c825c..98fcac8d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -27,6 +27,7 @@ src_filter = + + + + + + + @@ -42,6 +43,7 @@ build_flags = -Isrc/tft -Isrc/lib -Isrc/lib/printf + -Isrc/lib/tinyalloc -Isrc/lib/tinyusb/src ;DEBUG OUTPUT CONFIG -DDEBUG_STATUS=1 ;General information @@ -61,6 +63,9 @@ build_flags = -DPRINTF_DISABLE_SUPPORT_LONG_LONG -DPRINTF_DISABLE_SUPPORT_PTRDIFF_T + ; Tinyalloc Configuration + -DTA_DISABLE_COMPACT + [env:teensy41] platform = teensy@~4.13.1 board = teensy41 @@ -90,6 +95,35 @@ build_flags = -DCFG_TUSB_MCU=OPT_MCU_MIMXRT10XX -DMCU_VARIANT=MIMXRT1062 +[env:disco_f750n8] +platform = ststm32 +board = disco_f750n8_extflash +framework = stm32cube +; This board has hardly any internal flash. My code is booted from the QSPI external flash. +; This custom linker will copy all code to RAM after boot for noticably better performance. +; I also created code/data areas for flash when I want functions/data to remain on flash to save RAM. +board_build.ldscript = src/port_stm32f7/stm37f750-dk/STM32F750N8HX_EXTFLASH.ld + +src_filter = + ${common_env_data.src_filter} + + + + + + + + + + + + + +build_flags = + ${common_env_data.build_flags} + -Isrc/port_stm32f7/stm37f750-dk + -Isrc/port_stm32f7/common/fatfs + -Isrc/port_stm32f7/common/fatfs/drivers + -Isrc/port_stm32f7/common/bsp_drivers/STM32F7508-Discovery + -DCFG_TUSB_MCU=OPT_MCU_STM32F7 + -DAPPLICATION_ADDRESS=0x90000000U ;My entry point is in QSPI Flash for this board + -DUSE_HAL_DRIVER + -DSTM32F750xx + [env:null] platform = native From 730e89b35d5ad0f0265f8d43da043dd0668007d3 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 21 Dec 2021 09:05:18 +1030 Subject: [PATCH 081/121] TFT: Use standard malloc for tft log, stop recursive logging --- src/tft.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tft.cpp b/src/tft.cpp index 6e4e97ee..4b268195 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -285,7 +285,7 @@ void tft_add_log(char c) if (c == '\n') { tft_log[tft_log_pos] = '\0'; - _tft_log_text_lines[tft_log_line_num] = (char *)memory_dev_malloc(strlen(tft_log) + 1); + _tft_log_text_lines[tft_log_line_num] = (char *)malloc(strlen(tft_log) + 1); if (_tft_log_text_lines[tft_log_line_num] != NULL) { strcpy(_tft_log_text_lines[tft_log_line_num], tft_log); @@ -302,7 +302,7 @@ void tft_add_log(char c) //Exceeded max lines, remove oldest line and shift lines up by one if (tft_log_line_num >= _tft_log_max_lines) { - memory_dev_free(_tft_log_text_lines[0]); + free(_tft_log_text_lines[0]); for (uint32_t i = 0; i < _tft_log_max_lines - 1; i++) { _tft_log_text_lines[i] = _tft_log_text_lines[i + 1]; From b280e81f89a3b2cd506c07b2b50e0c2444074207 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 21 Dec 2021 09:06:16 +1030 Subject: [PATCH 082/121] tuh: Allow multiple hubs --- src/lib/tusb_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tusb_config.h b/src/lib/tusb_config.h index a2edfc2c..eb6f6da3 100644 --- a/src/lib/tusb_config.h +++ b/src/lib/tusb_config.h @@ -74,7 +74,7 @@ // Size of buffer to hold descriptors and other data used for enumeration #define CFG_TUH_ENUMERATION_BUFSIZE 256 -#define CFG_TUH_HUB 1 +#define CFG_TUH_HUB 4 #define CFG_TUH_CDC 0 #define CFG_TUH_HID 4 // typical keyboard + mouse device can have 3-4 HID interfaces #define CFG_TUH_MSC 0 From 4f33489486d825abf19c3739d6fc17496107aad3 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 21 Dec 2021 09:06:48 +1030 Subject: [PATCH 083/121] TinyUSB: Update submodule --- src/lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tinyusb b/src/lib/tinyusb index 5565ce05..4a61b7ac 160000 --- a/src/lib/tinyusb +++ b/src/lib/tinyusb @@ -1 +1 @@ -Subproject commit 5565ce0553112ae46bf49090c4c6b5908d7df361 +Subproject commit 4a61b7ac61c7cfefb80a3abfd0891adf105c545c From ca1bda9338a05b97771347d8f79eb55a527da0e8 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Thu, 6 Jan 2022 18:25:42 +1030 Subject: [PATCH 084/121] XINPUT: Dont parse callback if error --- src/lib/xinput_host.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lib/xinput_host.c b/src/lib/xinput_host.c index 35b372b4..2daa85d7 100644 --- a/src/lib/xinput_host.c +++ b/src/lib/xinput_host.c @@ -280,7 +280,11 @@ bool xinputh_set_config(uint8_t dev_addr, uint8_t itf_num) bool xinputh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - (void)result; + if (result != XFER_RESULT_SUCCESS) + { + return false; + } + uint8_t const dir = tu_edpt_dir(ep_addr); uint8_t const instance = get_instance_id_by_epaddr(dev_addr, ep_addr); xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); @@ -289,7 +293,7 @@ bool xinputh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, ui if (dir == TUSB_DIR_IN) { - TU_LOG2("Get Report callback (%u, %u)\r\n", dev_addr, instance); + TU_LOG2("Get Report callback (%u, %u, %u bytes)\r\n", dev_addr, instance, xferred_bytes); TU_LOG2_MEM(xid_itf->epin_buf, xferred_bytes, 2); if (xid_itf->type == XBOX360_WIRED) { From aa2add7c9744d687fc588762fe39c9b3cf9de8ea Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Thu, 6 Jan 2022 18:29:08 +1030 Subject: [PATCH 085/121] STM32F7 USBH: Rework, multiport hubs work, more devices at once --- src/port_stm32f7/common/stm32fxx_hcd.c | 361 +++++++++++++++++-------- 1 file changed, 250 insertions(+), 111 deletions(-) diff --git a/src/port_stm32f7/common/stm32fxx_hcd.c b/src/port_stm32f7/common/stm32fxx_hcd.c index 305e6dcd..51406dff 100644 --- a/src/port_stm32f7/common/stm32fxx_hcd.c +++ b/src/port_stm32f7/common/stm32fxx_hcd.c @@ -31,50 +31,115 @@ #if CFG_TUSB_MCU == OPT_MCU_STM32F7 #include "device/dcd.h" -#define NUM_PIPES 11 +//Have active pipes. STM32F7 is 12 for FS and 16 for HS +#define MAX_PIPES 12 +#ifndef MAX_ENDPOINTS +#define MAX_ENDPOINTS 16 +#endif +//The amount of shared channels reserved for interrupt transfer queue. If you are polling many interrupt endpoints +//increasing this can increase the overall responsiveness. +//This must be < MAX_PIPES, and must allow for free pipes for control, bulk and iso transfers +#ifndef INTR_CHANNELS +#define INTR_CHANNELS 1 +#endif +static uint8_t intr_lock[INTR_CHANNELS] = {0}; //Make sure we dont use a pipe thats already in use. -static HCD_HandleTypeDef hhcd; -static bool port_connected = 0; +typedef struct +{ + bool allocated; + bool active; + uint32_t last_frame; + uint8_t dev_addr; + uint8_t ch_num; + uint8_t ep_type; + tusb_desc_endpoint_t ep_desc; + uint8_t *xfer_buff; + uint32_t xfer_len; + uint8_t toggle_in; + uint8_t toggle_out; +} usbh_endpoint_t; -//For an IN, this field is the buffer size that the application has reserved for the transfer. The -//application is expected to program this field as an integer multiple of the maximum packet -//size for IN transactions (periodic and non-periodic). -//FIXME, how to make this more efficient? -static uint8_t _local_buffer[512]; -static uint32_t user_len; -static uint8_t *user_buff; +usbh_endpoint_t usbh_endpoint[MAX_ENDPOINTS] = {0}; -static uint8_t _alloc_pipe() +static HCD_HandleTypeDef hhcd; +static bool root_port_connected = 0; + +static usbh_endpoint_t *_alloc_endpoint(uint8_t dev_addr, tusb_desc_endpoint_t *ep_desc) { - for (int i = 0; i < NUM_PIPES; i++) + for (int i = 0; i < MAX_ENDPOINTS; i++) { - if (hhcd.hc[i].max_packet == 0) + if (usbh_endpoint[i].allocated == false) { - TU_LOG3("Allocated pipe %d\n\n\n", i); - return i; + tu_memclr(&usbh_endpoint[i], sizeof(usbh_endpoint_t)); + usbh_endpoint[i].allocated = true; + usbh_endpoint[i].dev_addr = dev_addr; + memcpy(&usbh_endpoint[i].ep_desc, ep_desc, sizeof(tusb_desc_endpoint_t)); + switch (ep_desc->bmAttributes.xfer) + { + case TUSB_XFER_CONTROL: + usbh_endpoint[i].ep_type = EP_TYPE_CTRL; + break; + case TUSB_XFER_ISOCHRONOUS: + usbh_endpoint[i].ep_type = EP_TYPE_ISOC; + break; + case TUSB_XFER_BULK: + usbh_endpoint[i].ep_type = EP_TYPE_BULK; + break; + case TUSB_XFER_INTERRUPT: + usbh_endpoint[i].ep_type = EP_TYPE_INTR; + break; + } + + usbh_endpoint[i].ch_num = 0xFF; + //Interrupt endpoints share host channels. Scheduled in SOF + if (usbh_endpoint[i].ep_type == EP_TYPE_INTR) + { + usbh_endpoint[i].ch_num = 0; + } + else + { + //First 2 channels are reserved for interrupt endpoints (in and out) + for (int ch_num = INTR_CHANNELS; ch_num < MAX_PIPES; ch_num++) + { + if (hhcd.hc[ch_num].max_packet == 0) + { + usbh_endpoint[i].ch_num = ch_num; + break; + } + } + } + if (usbh_endpoint[i].ch_num != 0xFF) + { + return &usbh_endpoint[i]; + } + else + { + break; + } } } - TU_ASSERT(0); + return NULL; } -static uint8_t _find_pipe(uint8_t dev_addr, uint8_t ep_addr) +static usbh_endpoint_t *_find_endpoint(uint8_t dev_addr, uint8_t ep_addr) { - //For control pipe we share the input and output pipe, so remove the direction bit. - if ((ep_addr & 0x7F) == 0) + //If it's a control pipe, remove direction bit. Use same endpoint for IN/OUT + if (ep_addr == 0x80) { - ep_addr &= 0x7F; + ep_addr = 0x00; } - for (int i = 0; i < NUM_PIPES; i++) + for (int i = 0; i < MAX_ENDPOINTS; i++) { - //STM HC pipes dont store the direction bit in the ep num filed, so re-add from ep_is_in it if not a control pipe so we can find it. - uint8_t hc_ep_addr = hhcd.hc[i].ep_num | ((hhcd.hc[i].ep_is_in && ep_addr != 0x00) ? 0x80 : 0x00); - if ((hhcd.hc[i].dev_addr == dev_addr) && (hc_ep_addr == ep_addr)) + if (usbh_endpoint[i].allocated == false) { - TU_LOG2("Found pipe in slot %d for address %02x, ep_addr %02x\n", i, dev_addr, ep_addr); - return i; + continue; + } + if (usbh_endpoint[i].dev_addr == dev_addr && usbh_endpoint[i].ep_desc.bEndpointAddress == ep_addr) + { + return &usbh_endpoint[i]; } } - TU_ASSERT(0); + return NULL; } static void deferred_resetport(void *param) @@ -88,7 +153,7 @@ void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd) { //Need the reset port after connection to properly enable it. //Create a event to be handled outside the ISR. - port_connected = true; + root_port_connected = true; hcd_event_t event = { .event_id = USBH_EVENT_FUNC_CALL, @@ -101,39 +166,109 @@ void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd) void HAL_HCD_Disconnect_Callback(HCD_HandleTypeDef *hhcd) { TU_LOG3("%s\n", __FUNCTION__); - port_connected = 0; + root_port_connected = 0; hcd_event_device_remove(0, true); } -void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum, HCD_URBStateTypeDef urb_state) +void HAL_HCD_SOF_Callback(HCD_HandleTypeDef *hhcd) { - HCD_HCTypeDef *hc = &hhcd->hc[chnum]; + //Handle all queued interrupt transfers + static int intr_in_queue_head = 0; + int intr_channel = 0; + for (int i = intr_in_queue_head; i < (MAX_ENDPOINTS + intr_in_queue_head); i++) + { + if (intr_channel >= INTR_CHANNELS) + { + return; + } + uint8_t ep_index = i % MAX_ENDPOINTS; + if (!usbh_endpoint[ep_index].active) + { + continue; + } + + usbh_endpoint_t *ep = &usbh_endpoint[ep_index]; + + if (ep->ep_type == EP_TYPE_INTR && intr_lock[intr_channel] == 0) + { + if ((HAL_HCD_GetCurrentFrame(hhcd) - ep->last_frame) >= ep->ep_desc.bInterval) + { + //Get the currently active channel and store the toggle values + HCD_HCTypeDef *hc = &hhcd->hc[intr_channel]; + uint8_t old_ep_addr = hc->ep_num | ((hc->ep_is_in) ? 0x80 : 0x00); + usbh_endpoint_t *old_ep = _find_endpoint(hc->dev_addr, old_ep_addr); + if (old_ep != NULL) + { + old_ep->toggle_in = hc->toggle_in; + old_ep->toggle_out = hc->toggle_out; + } + else + { + TU_LOG1("ERROR, could not find ep\n"); + } + + //TU_LOG1("inter %d\n", ep->ep_desc.bInterval); + ep->ch_num = intr_channel; + HAL_HCD_HC_Init(hhcd, + ep->ch_num, + ep->ep_desc.bEndpointAddress, + ep->dev_addr, + HAL_HCD_GetCurrentSpeed(hhcd), //FIXME tuh_speed_get? + ep->ep_type, + ep->ep_desc.wMaxPacketSize); + hc->toggle_in = ep->toggle_in; + hc->toggle_out = ep->toggle_out; + HAL_HCD_HC_SubmitRequest(hhcd, + ep->ch_num, + (tu_edpt_dir(ep->ep_desc.bEndpointAddress) == TUSB_DIR_IN) ? 1 : 0, + ep->ep_type, + 1, + ep->xfer_buff, + ep->xfer_len, + 0); + ep->last_frame = HAL_HCD_GetCurrentFrame(hhcd); + intr_in_queue_head = (i + 1) % MAX_ENDPOINTS; + intr_lock[intr_channel] = ep->dev_addr; + intr_channel++; + //TU_LOG1("tx: %02x %d\n", ep->dev_addr, ep->toggle_in); + } + } + } +} + +void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t ch_num, HCD_URBStateTypeDef urb_state) +{ + HCD_HCTypeDef *hc = &hhcd->hc[ch_num]; uint8_t ep_addr = hc->ep_num | ((hc->ep_is_in) ? 0x80 : 0x00); - if (urb_state == URB_DONE) + usbh_endpoint_t *ep = _find_endpoint(hc->dev_addr, ep_addr); + uint32_t actual_length = HAL_HCD_HC_GetXferCount(hhcd, ch_num); + + //Interrupt transfer is done, stop the transfer. Wait for user callback to reschedule + if (hc->ep_type == EP_TYPE_INTR) { -/* - if (hc->ep_is_in && user_buff) + if ((urb_state == URB_DONE || urb_state == URB_STALL || urb_state == URB_ERROR)) { - memcpy(user_buff, _local_buffer, user_len); + ep->active = 0; } -*/ - TU_LOG3("Transfer SUCCESS devadr%02x ep:%02x\n", hc->dev_addr, ep_addr); - hcd_event_xfer_complete(hc->dev_addr, ep_addr, hc->xfer_len, XFER_RESULT_SUCCESS, true); + intr_lock[ch_num] = 0; } - else if (urb_state == URB_STALL) + + if (urb_state == URB_DONE) { - TU_LOG1("Transfer ERROR: URB_STALL\n"); - hcd_event_xfer_complete(hc->dev_addr, ep_addr, hc->xfer_len, XFER_RESULT_STALLED, true); + TU_LOG3("Transfer SUCCESS devadr%02x ep:%02x %d bytes\n", hc->dev_addr, ep_addr, actual_length); + hcd_event_xfer_complete(hc->dev_addr, ep_addr, actual_length, XFER_RESULT_SUCCESS, true); } - else if (urb_state == URB_ERROR) + else if (urb_state == URB_STALL) { - hcd_event_xfer_complete(hc->dev_addr, ep_addr, hc->xfer_len, XFER_RESULT_FAILED, true); - TU_LOG1("Transfer ERROR: URB_ERROR\n"); + TU_LOG1("Transfer ERROR: URB_STALL, state %02x dev addr: %02x\n", hc->state, hc->dev_addr); + hc->state = HC_IDLE; + hcd_event_xfer_complete(hc->dev_addr, ep_addr, actual_length, XFER_RESULT_STALLED, true); } - else if (urb_state == URB_IDLE || urb_state == URB_IDLE) + else if (urb_state == URB_ERROR) { - //Resubmit URB (this happens sometimes) - HAL_HCD_HC_SubmitRequest(hhcd, chnum, hc->ep_is_in, hc->ep_type, 1, hc->xfer_buff, hc->xfer_len, 0); + TU_LOG1("Transfer ERROR: URB_ERROR, state %02x dev addr: %02x\n", hc->state, hc->dev_addr); + hc->state = HC_IDLE; + hcd_event_xfer_complete(hc->dev_addr, ep_addr, actual_length, XFER_RESULT_FAILED, true); } } @@ -141,13 +276,25 @@ void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum, void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { (void)rhport; - for (int i = 0; i < NUM_PIPES + 1; i++) + for (int i = 0; i < MAX_ENDPOINTS; i++) { - if (hhcd.hc[i].dev_addr == dev_addr && hhcd.hc[i].max_packet > 0) + usbh_endpoint_t *ep = &usbh_endpoint[i]; + if (ep->allocated == true && ep->dev_addr == dev_addr) { - TU_LOG3("Closing pipe %d\n", i); - HAL_HCD_HC_Halt(&hhcd, i); - tu_memclr(&hhcd.hc[i], sizeof(HCD_HCTypeDef)); + TU_LOG1("Closing pipe %d on dev %02x\n", i, dev_addr); + if (hhcd.hc[ep->ch_num].dev_addr == ep->dev_addr) + { + tu_memclr(&hhcd.hc[ep->ch_num], sizeof(HCD_HCTypeDef)); + } + tu_memclr(ep, sizeof(usbh_endpoint_t)); + } + } + //Release any interrupt channel locks + for (int i = 0; i < INTR_CHANNELS; i++) + { + if (intr_lock[i] == dev_addr) + { + intr_lock[i] = 0; } } } @@ -176,7 +323,7 @@ uint32_t hcd_frame_number(uint8_t rhport) bool hcd_port_connect_status(uint8_t rhport) { (void)rhport; - return port_connected; + return root_port_connected; } // Reset USB bus on the port @@ -210,11 +357,11 @@ bool hcd_init(uint8_t rhport) (void)rhport; HAL_StatusTypeDef res = HAL_ERROR; hhcd.Instance = USB_OTG_FS; - hhcd.Init.Host_channels = NUM_PIPES; + hhcd.Init.Host_channels = MAX_PIPES; hhcd.Init.dma_enable = 0; hhcd.Init.low_power_enable = 0; hhcd.Init.phy_itface = HCD_PHY_EMBEDDED; - hhcd.Init.Sof_enable = 0; + hhcd.Init.Sof_enable = 1; hhcd.Init.speed = HCD_SPEED_FULL; hhcd.Init.vbus_sensing_enable = 0; hhcd.Init.lpm_enable = 0; @@ -233,85 +380,74 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const TU_LOG3("%s\n", __FUNCTION__); int ret = HAL_OK; - uint8_t ep_type = EP_TYPE_CTRL; - switch (ep_desc->bmAttributes.xfer) + usbh_endpoint_t *new_ep = _alloc_endpoint(dev_addr, (tusb_desc_endpoint_t *)ep_desc); + TU_ASSERT(new_ep != NULL); + if (new_ep->ep_type != EP_TYPE_INTR) { - case TUSB_XFER_CONTROL: - ep_type = EP_TYPE_CTRL; - break; - case TUSB_XFER_ISOCHRONOUS: - ep_type = EP_TYPE_ISOC; - break; - case TUSB_XFER_BULK: - ep_type = EP_TYPE_BULK; - break; - case TUSB_XFER_INTERRUPT: - ep_type = EP_TYPE_INTR; - break; + //For non interrupt endpoints, I allocate a pipe in the host controller immediately. + tu_memclr(&hhcd.hc[new_ep->ch_num], sizeof(HCD_HCTypeDef)); + TU_ASSERT(ep_desc->wMaxPacketSize > 0); //FIXME?, I rely on mps > 0 for pipe allocation + ret = HAL_HCD_HC_Init(&hhcd, + new_ep->ch_num, + new_ep->ep_desc.bEndpointAddress, + new_ep->dev_addr, + HAL_HCD_GetCurrentSpeed(&hhcd), //FIXME tuh_speed_get? + new_ep->ep_type, + new_ep->ep_desc.wMaxPacketSize); } - uint8_t ch_num = _alloc_pipe(); - tu_memclr(&hhcd.hc[ch_num], sizeof(HCD_HCTypeDef)); - TU_ASSERT(ep_desc->wMaxPacketSize > 0); //FIXME?, I relay on mps > 0 for pipe allocation - ret = HAL_HCD_HC_Init(&hhcd, ch_num, ep_desc->bEndpointAddress, dev_addr, HAL_HCD_GetCurrentSpeed(&hhcd), ep_type, ep_desc->wMaxPacketSize); - TU_LOG3("Opened pipe for devaddr:%d epaddr:%02x in slot %d\n", dev_addr, ep_desc->bEndpointAddress, ch_num); + TU_LOG1("Opened pipe for devaddr:%d epaddr:%02x in slot %d\n", dev_addr, new_ep->ep_desc.bEndpointAddress, new_ep->ch_num); return (ret == HAL_OK); } bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { (void)rhport; - uint8_t ch_num = _find_pipe(dev_addr, 0x00); - + TU_LOG3("%s\n", __FUNCTION__); + usbh_endpoint_t *ep = _find_endpoint(dev_addr, 0x00); HAL_StatusTypeDef ret = HAL_HCD_HC_SubmitRequest(&hhcd, - ch_num, + ep->ch_num, 0, EP_TYPE_CTRL, 0, (uint8_t *)setup_packet, 8, 0); - return ret == HAL_OK; + return (ret == HAL_OK); } bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen) { (void)rhport; + HAL_StatusTypeDef ret = HAL_OK; + usbh_endpoint_t *ep = _find_endpoint(dev_addr, ep_addr); + TU_ASSERT(ep != NULL); - tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr); - uint8_t ch_num = _find_pipe(dev_addr, ep_addr); - TU_LOG2("hcd_edpt_xfer on pipe for devaddr:%d epaddr:%02x in slot %d, ep_type %d, ep_dir %d, len %d, togglein %d dir bool %d\n", - dev_addr, ep_addr, ch_num, hhcd.hc[ch_num].ep_type, ep_dir, buflen, hhcd.hc[ch_num].toggle_in, (ep_dir == TUSB_DIR_IN) ? 1 : 0); + ep->active = 1; + ep->xfer_buff = buffer; + ep->xfer_len = buflen; - if (hhcd.hc[ch_num].urb_state == URB_NOTREADY || hhcd.hc[ch_num].urb_state == URB_NYET || (hhcd.hc[ch_num].state != HC_IDLE && hhcd.hc[ch_num].state != HC_XFRC)) + if (ep->ep_type != EP_TYPE_INTR) { - TU_LOG1("Error: Endpoint %02x is busy, urb: %02x hc: %02x\n", ep_addr, hhcd.hc[ch_num].urb_state, hhcd.hc[ch_num].state); - TU_ASSERT(0); + HCD_HCTypeDef *hc = &hhcd.hc[ep->ch_num]; + if (hc->urb_state == URB_NOTREADY || hc->urb_state == URB_NYET || + (hc->state != HC_IDLE && hc->state != HC_XFRC)) + { + TU_LOG1("Error: Endpoint %02x is busy, urb: %02x hc: %02x\n", ep_addr, hc->urb_state, hc->state); + TU_ASSERT(0); + } + ret = HAL_HCD_HC_SubmitRequest(&hhcd, + ep->ch_num, + (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) ? 1 : 0, + ep->ep_type, + 1, + buffer, + buflen, + 0); } -/* - //FXIME. STM32F7 expects packets in multiples of maxpacket size. TinyUSB doesnt always do this so can overflow buffers - if ((ep_dir == TUSB_DIR_IN && (buflen % hhcd.hc[ch_num].max_packet != 0))) - { - TU_ASSERT(buflen < sizeof(_local_buffer)); - user_buff = buffer; - user_len = buflen; - buffer = _local_buffer; - } - else - { - user_buff = NULL; - } -*/ + TU_LOG2("hcd_edpt_xfer on pipe for devaddr:%d epaddr:%02x in slot %d, ep_type %d, ep_dir %d, len %d\n", + dev_addr, ep_addr, ep->ch_num, ep->ep_type, tu_edpt_dir(ep_addr), buflen); - HAL_StatusTypeDef ret = HAL_HCD_HC_SubmitRequest(&hhcd, - ch_num, - (ep_dir == TUSB_DIR_IN) ? 1 : 0, - hhcd.hc[ch_num].ep_type, - 1, - buffer, - buflen, - 0); - return (ret == HAL_OK); } @@ -322,9 +458,12 @@ void hcd_int_handler(uint8_t rhport) bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr) { - uint8_t ch_num = _find_pipe(dev_addr, ep_addr); - hhcd.hc[ch_num].urb_state = URB_IDLE; + usbh_endpoint_t *ep = _find_endpoint(dev_addr, ep_addr); + if (ep != NULL) + { + hhcd.hc[ep->ch_num].urb_state = URB_IDLE; + } return true; } -#endif +#endif \ No newline at end of file From 32eed1d18192d65d1627b8f4e88de0ecbbb4fef5 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Thu, 6 Jan 2022 18:41:17 +1030 Subject: [PATCH 086/121] Tinyusb: Update submodule --- src/lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tinyusb b/src/lib/tinyusb index 4a61b7ac..13a22219 160000 --- a/src/lib/tinyusb +++ b/src/lib/tinyusb @@ -1 +1 @@ -Subproject commit 4a61b7ac61c7cfefb80a3abfd0891adf105c545c +Subproject commit 13a2221965d18fc7dedad4b750610149febd8bca From 77933bf1c2f5f5a0a7b61d04ad4fdbeaf6f60153 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Thu, 6 Jan 2022 19:11:18 +1030 Subject: [PATCH 087/121] stm32f7: Disable USB IRQ too --- src/port_stm32f7/stm37f750-dk/hal_stm32.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/port_stm32f7/stm37f750-dk/hal_stm32.cpp b/src/port_stm32f7/stm37f750-dk/hal_stm32.cpp index 1e6eb5ff..32a7b618 100644 --- a/src/port_stm32f7/stm37f750-dk/hal_stm32.cpp +++ b/src/port_stm32f7/stm37f750-dk/hal_stm32.cpp @@ -186,6 +186,7 @@ void n64hal_disable_interrupts() HAL_NVIC_DisableIRQ(EXTI9_5_IRQn); HAL_NVIC_DisableIRQ(EXTI2_IRQn); HAL_NVIC_DisableIRQ(EXTI3_IRQn); + HAL_NVIC_DisableIRQ(OTG_FS_IRQn); } void n64hal_enable_interrupts() @@ -194,6 +195,7 @@ void n64hal_enable_interrupts() HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); HAL_NVIC_EnableIRQ(EXTI2_IRQn); HAL_NVIC_EnableIRQ(EXTI3_IRQn); + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); } void n64hal_attach_interrupt(usb64_pin_t pin, void (*handler)(void), int mode) From 85a6ab003d4f9eebbc6982db616ae4a22ff31d56 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sun, 9 Jan 2022 16:22:16 +1030 Subject: [PATCH 088/121] TinyUSB: Update submodule --- src/lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tinyusb b/src/lib/tinyusb index 13a22219..c133be3e 160000 --- a/src/lib/tinyusb +++ b/src/lib/tinyusb @@ -1 +1 @@ -Subproject commit 13a2221965d18fc7dedad4b750610149febd8bca +Subproject commit c133be3e36919cb872f43d1bd8503c986c047c1f From 532d03d8e6015febe13d242c8f322d88b22e23c3 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sun, 9 Jan 2022 16:22:52 +1030 Subject: [PATCH 089/121] USBH: Increase enumeration buffer size --- src/lib/tusb_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tusb_config.h b/src/lib/tusb_config.h index eb6f6da3..89ec9654 100644 --- a/src/lib/tusb_config.h +++ b/src/lib/tusb_config.h @@ -72,7 +72,7 @@ //-------------------------------------------------------------------- // Size of buffer to hold descriptors and other data used for enumeration -#define CFG_TUH_ENUMERATION_BUFSIZE 256 +#define CFG_TUH_ENUMERATION_BUFSIZE 512 #define CFG_TUH_HUB 4 #define CFG_TUH_CDC 0 From 1e8faf2f0b2ebbecf9f5fb8e7330c044fd82e72c Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sun, 9 Jan 2022 16:25:03 +1030 Subject: [PATCH 090/121] stm32f7 usbh: Share control pipe, refactor functions --- src/port_stm32f7/common/stm32fxx_hcd.c | 230 +++++++++++++------------ 1 file changed, 117 insertions(+), 113 deletions(-) diff --git a/src/port_stm32f7/common/stm32fxx_hcd.c b/src/port_stm32f7/common/stm32fxx_hcd.c index 51406dff..cdd01981 100644 --- a/src/port_stm32f7/common/stm32fxx_hcd.c +++ b/src/port_stm32f7/common/stm32fxx_hcd.c @@ -2,6 +2,7 @@ * The MIT License (MIT) * * Copyright (c) 2018, hathach (tinyusb.org) + * Copyright (c) 2022, Ryzee119 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,18 +32,26 @@ #if CFG_TUSB_MCU == OPT_MCU_STM32F7 #include "device/dcd.h" -//Have active pipes. STM32F7 is 12 for FS and 16 for HS +static HCD_HandleTypeDef hhcd; +static bool root_port_connected = 0; + +//STM32F7 is 12 for FS and 16 for HS #define MAX_PIPES 12 #ifndef MAX_ENDPOINTS -#define MAX_ENDPOINTS 16 +#define MAX_ENDPOINTS 32 #endif + //The amount of shared channels reserved for interrupt transfer queue. If you are polling many interrupt endpoints //increasing this can increase the overall responsiveness. -//This must be < MAX_PIPES, and must allow for free pipes for control, bulk and iso transfers +//This must be < MAX_PIPES, and MAX_ENDPOINTS - INTR_CHANNELS must allow for free pipes for control, bulk and iso transfers #ifndef INTR_CHANNELS -#define INTR_CHANNELS 1 +#define INTR_CHANNELS 6 #endif -static uint8_t intr_lock[INTR_CHANNELS] = {0}; //Make sure we dont use a pipe thats already in use. +//Single shared control channel just after the reserved interrupt channels +#define CTRL_CHANNEL INTR_CHANNELS + +//Locks to make sure we dont use a interrupt pipe thats already in use. +static uint8_t intr_lock[INTR_CHANNELS] = {0}; typedef struct { @@ -55,15 +64,11 @@ typedef struct tusb_desc_endpoint_t ep_desc; uint8_t *xfer_buff; uint32_t xfer_len; - uint8_t toggle_in; - uint8_t toggle_out; + uint8_t toggle; } usbh_endpoint_t; usbh_endpoint_t usbh_endpoint[MAX_ENDPOINTS] = {0}; -static HCD_HandleTypeDef hhcd; -static bool root_port_connected = 0; - static usbh_endpoint_t *_alloc_endpoint(uint8_t dev_addr, tusb_desc_endpoint_t *ep_desc) { for (int i = 0; i < MAX_ENDPOINTS; i++) @@ -96,14 +101,19 @@ static usbh_endpoint_t *_alloc_endpoint(uint8_t dev_addr, tusb_desc_endpoint_t * { usbh_endpoint[i].ch_num = 0; } + else if (usbh_endpoint[i].ep_type == EP_TYPE_CTRL) + { + usbh_endpoint[i].ch_num = CTRL_CHANNEL; + } + //Bulk and iso are allocated their own channel, allocated after interrupt and control channels else { - //First 2 channels are reserved for interrupt endpoints (in and out) - for (int ch_num = INTR_CHANNELS; ch_num < MAX_PIPES; ch_num++) + for (int ch_num = CTRL_CHANNEL; ch_num < MAX_PIPES; ch_num++) { if (hhcd.hc[ch_num].max_packet == 0) { usbh_endpoint[i].ch_num = ch_num; + hhcd.hc[ch_num].max_packet = 8; //Set to a standard non-zero number. break; } } @@ -114,6 +124,7 @@ static usbh_endpoint_t *_alloc_endpoint(uint8_t dev_addr, tusb_desc_endpoint_t * } else { + TU_LOG1("ERROR: No more host channels!\n"); break; } } @@ -123,11 +134,6 @@ static usbh_endpoint_t *_alloc_endpoint(uint8_t dev_addr, tusb_desc_endpoint_t * static usbh_endpoint_t *_find_endpoint(uint8_t dev_addr, uint8_t ep_addr) { - //If it's a control pipe, remove direction bit. Use same endpoint for IN/OUT - if (ep_addr == 0x80) - { - ep_addr = 0x00; - } for (int i = 0; i < MAX_ENDPOINTS; i++) { if (usbh_endpoint[i].allocated == false) @@ -142,10 +148,45 @@ static usbh_endpoint_t *_find_endpoint(uint8_t dev_addr, uint8_t ep_addr) return NULL; } +static bool _endpoint_xfer(usbh_endpoint_t *ep, uint8_t is_setup) +{ + HAL_StatusTypeDef ret = HAL_OK; + HCD_HCTypeDef *hc = &hhcd.hc[ep->ch_num]; + uint8_t hc_ep_addr = hc->ep_num | ((hc->ep_is_in) ? 0x80 : 0x00); + if (hc->dev_addr != ep->dev_addr || hc_ep_addr != ep->ep_desc.bEndpointAddress || hc->dev_addr == 0) + { + ret = HAL_HCD_HC_Init(&hhcd, + ep->ch_num, + ep->ep_desc.bEndpointAddress, + ep->dev_addr, + HAL_HCD_GetCurrentSpeed(&hhcd), //FIXME tuh_speed_get? + ep->ep_type, + ep->ep_desc.wMaxPacketSize); + } + + uint8_t *toggle = (hc->ep_is_in) ? &hc->toggle_in : &hc->toggle_out; + *toggle = ep->toggle; + + ep->active = 1; + ep->last_frame = HAL_HCD_GetCurrentFrame(&hhcd); + + if (ret == HAL_OK) + { + ret = HAL_HCD_HC_SubmitRequest(&hhcd, + ep->ch_num, + (tu_edpt_dir(ep->ep_desc.bEndpointAddress) == TUSB_DIR_IN) ? 1 : 0, + ep->ep_type, + (is_setup) ? 0 : 1, + (uint8_t *)ep->xfer_buff, + ep->xfer_len, + 0); + } + return (ret == HAL_OK); +} + static void deferred_resetport(void *param) { HAL_HCD_ResetPort(&hhcd); - //Device is reset, alert TinyUSB. hcd_event_device_attach(0, false); } @@ -165,7 +206,6 @@ void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd) void HAL_HCD_Disconnect_Callback(HCD_HandleTypeDef *hhcd) { - TU_LOG3("%s\n", __FUNCTION__); root_port_connected = 0; hcd_event_device_remove(0, true); } @@ -181,56 +221,24 @@ void HAL_HCD_SOF_Callback(HCD_HandleTypeDef *hhcd) { return; } + uint8_t ep_index = i % MAX_ENDPOINTS; - if (!usbh_endpoint[ep_index].active) + usbh_endpoint_t *ep = &usbh_endpoint[ep_index]; + + if (ep->active == 0) { continue; } - usbh_endpoint_t *ep = &usbh_endpoint[ep_index]; - if (ep->ep_type == EP_TYPE_INTR && intr_lock[intr_channel] == 0) { if ((HAL_HCD_GetCurrentFrame(hhcd) - ep->last_frame) >= ep->ep_desc.bInterval) { - //Get the currently active channel and store the toggle values - HCD_HCTypeDef *hc = &hhcd->hc[intr_channel]; - uint8_t old_ep_addr = hc->ep_num | ((hc->ep_is_in) ? 0x80 : 0x00); - usbh_endpoint_t *old_ep = _find_endpoint(hc->dev_addr, old_ep_addr); - if (old_ep != NULL) - { - old_ep->toggle_in = hc->toggle_in; - old_ep->toggle_out = hc->toggle_out; - } - else - { - TU_LOG1("ERROR, could not find ep\n"); - } - - //TU_LOG1("inter %d\n", ep->ep_desc.bInterval); ep->ch_num = intr_channel; - HAL_HCD_HC_Init(hhcd, - ep->ch_num, - ep->ep_desc.bEndpointAddress, - ep->dev_addr, - HAL_HCD_GetCurrentSpeed(hhcd), //FIXME tuh_speed_get? - ep->ep_type, - ep->ep_desc.wMaxPacketSize); - hc->toggle_in = ep->toggle_in; - hc->toggle_out = ep->toggle_out; - HAL_HCD_HC_SubmitRequest(hhcd, - ep->ch_num, - (tu_edpt_dir(ep->ep_desc.bEndpointAddress) == TUSB_DIR_IN) ? 1 : 0, - ep->ep_type, - 1, - ep->xfer_buff, - ep->xfer_len, - 0); - ep->last_frame = HAL_HCD_GetCurrentFrame(hhcd); + _endpoint_xfer(ep, 0); intr_in_queue_head = (i + 1) % MAX_ENDPOINTS; intr_lock[intr_channel] = ep->dev_addr; intr_channel++; - //TU_LOG1("tx: %02x %d\n", ep->dev_addr, ep->toggle_in); } } } @@ -246,30 +254,42 @@ void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t ch_num //Interrupt transfer is done, stop the transfer. Wait for user callback to reschedule if (hc->ep_type == EP_TYPE_INTR) { - if ((urb_state == URB_DONE || urb_state == URB_STALL || urb_state == URB_ERROR)) - { - ep->active = 0; - } intr_lock[ch_num] = 0; } if (urb_state == URB_DONE) { - TU_LOG3("Transfer SUCCESS devadr%02x ep:%02x %d bytes\n", hc->dev_addr, ep_addr, actual_length); + TU_LOG2("Transfer SUCCESS devaddr %02x ep:%02x %d bytes, channel %d\n", hc->dev_addr, ep_addr, actual_length, ch_num); + ep->toggle = (hc->ep_is_in) ? hc->toggle_in ^ 1 : hc->toggle_out; + ep->active = 0; hcd_event_xfer_complete(hc->dev_addr, ep_addr, actual_length, XFER_RESULT_SUCCESS, true); } else if (urb_state == URB_STALL) { - TU_LOG1("Transfer ERROR: URB_STALL, state %02x dev addr: %02x\n", hc->state, hc->dev_addr); + TU_LOG1("Transfer ERROR: URB_STALL, state %02x dev addr: %02x channel %d\n", hc->state, hc->dev_addr, ch_num); hc->state = HC_IDLE; + ep->active = 0; hcd_event_xfer_complete(hc->dev_addr, ep_addr, actual_length, XFER_RESULT_STALLED, true); } - else if (urb_state == URB_ERROR) + else if (urb_state == URB_ERROR || hc->state == HC_XACTERR) { - TU_LOG1("Transfer ERROR: URB_ERROR, state %02x dev addr: %02x\n", hc->state, hc->dev_addr); + TU_LOG1("Transfer ERROR: URB_ERROR, state %02x dev addr: %02x channel %d\n", hc->state, hc->dev_addr, ch_num); hc->state = HC_IDLE; + ep->active = 0; hcd_event_xfer_complete(hc->dev_addr, ep_addr, actual_length, XFER_RESULT_FAILED, true); } + //Automatically retry output NAK. + else if (urb_state == URB_NOTREADY && hc->state == HC_NAK && hc->ep_is_in == 0) + { + //Retry output NAK. FIXME? Retry count? Only for control endpoint? + uint32_t tmpreg; + USB_OTG_GlobalTypeDef *USBx = hhcd->Instance; + uint32_t USBx_BASE = (uint32_t)USBx; + tmpreg = USBx_HC(ch_num)->HCCHAR; + tmpreg &= ~USB_OTG_HCCHAR_CHDIS; + tmpreg |= USB_OTG_HCCHAR_CHENA; + USBx_HC(ch_num)->HCCHAR = tmpreg; + } } // HCD closes all opened endpoints belong to this device @@ -281,7 +301,7 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) usbh_endpoint_t *ep = &usbh_endpoint[i]; if (ep->allocated == true && ep->dev_addr == dev_addr) { - TU_LOG1("Closing pipe %d on dev %02x\n", i, dev_addr); + TU_LOG2("Closing pipe %d on dev %02x\n", i, dev_addr); if (hhcd.hc[ep->ch_num].dev_addr == ep->dev_addr) { tu_memclr(&hhcd.hc[ep->ch_num], sizeof(HCD_HCTypeDef)); @@ -377,78 +397,62 @@ bool hcd_init(uint8_t rhport) bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *ep_desc) { (void)rhport; - TU_LOG3("%s\n", __FUNCTION__); - int ret = HAL_OK; - usbh_endpoint_t *new_ep = _alloc_endpoint(dev_addr, (tusb_desc_endpoint_t *)ep_desc); - TU_ASSERT(new_ep != NULL); - if (new_ep->ep_type != EP_TYPE_INTR) + usbh_endpoint_t *ep = _alloc_endpoint(dev_addr, (tusb_desc_endpoint_t *)ep_desc); + TU_ASSERT(ep != NULL); + TU_LOG2("Opened pipe for devaddr:%d epaddr:%02x in slot %d\n", dev_addr, ep->ep_desc.bEndpointAddress, ep->ch_num); + if (ep_desc->bEndpointAddress == 0x00) { - //For non interrupt endpoints, I allocate a pipe in the host controller immediately. - tu_memclr(&hhcd.hc[new_ep->ch_num], sizeof(HCD_HCTypeDef)); - TU_ASSERT(ep_desc->wMaxPacketSize > 0); //FIXME?, I rely on mps > 0 for pipe allocation - ret = HAL_HCD_HC_Init(&hhcd, - new_ep->ch_num, - new_ep->ep_desc.bEndpointAddress, - new_ep->dev_addr, - HAL_HCD_GetCurrentSpeed(&hhcd), //FIXME tuh_speed_get? - new_ep->ep_type, - new_ep->ep_desc.wMaxPacketSize); + //If control endpoint, also opening IN pipe + ep = _alloc_endpoint(dev_addr, (tusb_desc_endpoint_t *)ep_desc); + ep->ep_desc.bEndpointAddress |= 0x80; + TU_ASSERT(ep != NULL); + TU_LOG2("Opened pipe for devaddr:%d epaddr:%02x in slot %d\n", dev_addr, ep->ep_desc.bEndpointAddress, ep->ch_num); } - TU_LOG1("Opened pipe for devaddr:%d epaddr:%02x in slot %d\n", dev_addr, new_ep->ep_desc.bEndpointAddress, new_ep->ch_num); - return (ret == HAL_OK); + return true; } bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { (void)rhport; - TU_LOG3("%s\n", __FUNCTION__); + usbh_endpoint_t *ep = _find_endpoint(dev_addr, 0x00); - HAL_StatusTypeDef ret = HAL_HCD_HC_SubmitRequest(&hhcd, - ep->ch_num, - 0, - EP_TYPE_CTRL, - 0, - (uint8_t *)setup_packet, - 8, - 0); - return (ret == HAL_OK); + TU_ASSERT(ep != NULL); + + ep->xfer_buff = (uint8_t *)setup_packet; + ep->xfer_len = 8; + + TU_LOG2("hcd_setup_send on pipe for devaddr:%d in slot %d, ep_type %d, len %d\n", + dev_addr, ep->ch_num, ep->ep_type, 8); + + return _endpoint_xfer(ep, 1); } bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen) { (void)rhport; - HAL_StatusTypeDef ret = HAL_OK; + bool ret = true; usbh_endpoint_t *ep = _find_endpoint(dev_addr, ep_addr); TU_ASSERT(ep != NULL); - ep->active = 1; ep->xfer_buff = buffer; ep->xfer_len = buflen; + TU_LOG2("hcd_edpt_xfer on pipe for devaddr:%d epaddr:%02x in slot %d, ep_type %d, ep_dir %d, len %d\n", + ep->dev_addr, ep->ep_desc.bEndpointAddress, ep->ch_num, ep->ep_type, tu_edpt_dir(ep_addr), buflen); + + //Non interrupt endpoints, queue immediately. if (ep->ep_type != EP_TYPE_INTR) { - HCD_HCTypeDef *hc = &hhcd.hc[ep->ch_num]; - if (hc->urb_state == URB_NOTREADY || hc->urb_state == URB_NYET || - (hc->state != HC_IDLE && hc->state != HC_XFRC)) - { - TU_LOG1("Error: Endpoint %02x is busy, urb: %02x hc: %02x\n", ep_addr, hc->urb_state, hc->state); - TU_ASSERT(0); - } - ret = HAL_HCD_HC_SubmitRequest(&hhcd, - ep->ch_num, - (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) ? 1 : 0, - ep->ep_type, - 1, - buffer, - buflen, - 0); + ret = _endpoint_xfer(ep, 0); + } + //Otherwise, mark it as after and it will be schedule in SOF interrupt + else + { + ep->active = 1; } - TU_LOG2("hcd_edpt_xfer on pipe for devaddr:%d epaddr:%02x in slot %d, ep_type %d, ep_dir %d, len %d\n", - dev_addr, ep_addr, ep->ch_num, ep->ep_type, tu_edpt_dir(ep_addr), buflen); - - return (ret == HAL_OK); + return ret; } void hcd_int_handler(uint8_t rhport) From 7a054e7cbc1a0d21b5a04b025a2d3faaa08344df Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sun, 9 Jan 2022 18:11:13 +1030 Subject: [PATCH 091/121] TinyUSB: Update submodule --- src/lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tinyusb b/src/lib/tinyusb index c133be3e..790466c7 160000 --- a/src/lib/tinyusb +++ b/src/lib/tinyusb @@ -1 +1 @@ -Subproject commit c133be3e36919cb872f43d1bd8503c986c047c1f +Subproject commit 790466c757df336b89a299682a6825fae3b4da90 From 71727a145af6641a24ea5f950482f7f043c0e561 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 11 Jan 2022 12:03:05 +1030 Subject: [PATCH 092/121] Input: Correctly handle wireless 360 controllers --- src/input.cpp | 32 +++++++++++++++--- src/input.h | 1 + src/lib/xinput_host.c | 75 +++++++++++++++++++++++++++++++++++++------ src/lib/xinput_host.h | 6 ++-- 4 files changed, 99 insertions(+), 15 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index 589e51be..ec44b4b7 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -28,6 +28,7 @@ static input_driver_t *find_slot(uint16_t uid) { if (input_devices[i].type == INPUT_NONE && uid == 0) { + input_devices[i].slot = i; return &input_devices[i]; } } @@ -36,17 +37,40 @@ static input_driver_t *find_slot(uint16_t uid) void tuh_xinput_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { + xinputh_interface_t *xid_itf = (xinputh_interface_t *)report; uint16_t uid = dev_addr << 8 | instance; input_driver_t *in_dev = find_slot(uid); - if (in_dev != NULL) + if (in_dev != NULL && xid_itf->new_pad_data == true) { - memcpy(in_dev->data, report, TU_MIN(len, CFG_TUH_XINPUT_EPIN_BUFSIZE)); + memcpy(in_dev->data, &xid_itf->pad, TU_MIN(len, CFG_TUH_XINPUT_EPIN_BUFSIZE)); + } + else if (in_dev == NULL && xid_itf->type == XBOX360_WIRELESS) + { + if (xid_itf->connected == true) + { + tuh_xinput_mount_cb(dev_addr, instance, xid_itf); + } + } + else if (in_dev != NULL && xid_itf->type == XBOX360_WIRELESS) + { + if (xid_itf->connected == false) + { + tuh_xinput_umount_cb(dev_addr, instance); + } } tuh_xinput_receive_report(dev_addr, instance); } -void tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, const tusb_desc_interface_t *desc_report) +void tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, const xinputh_interface_t *xinput_itf) { + //If this is a Xbox 360 Wireless controller, dont register yet. Need to wait for a connection packet + //on the in pipe. + if (xinput_itf->type == XBOX360_WIRELESS && xinput_itf->connected == false) + { + tuh_xinput_receive_report(dev_addr, instance); + return; + } + input_driver_t *in_dev = find_slot(0); in_dev->type = INPUT_GAMECONTROLLER; @@ -57,7 +81,7 @@ void tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, const tusb_desc_int in_dev->data = in_dev->_data; tuh_xinput_set_led(dev_addr, instance, 0, true); - tuh_xinput_set_led(dev_addr, instance, 1, true); + tuh_xinput_set_led(dev_addr, instance, in_dev->slot + 1, true); tuh_xinput_set_rumble(dev_addr, instance, 0, 0, true); tuh_xinput_receive_report(dev_addr, instance); } diff --git a/src/input.h b/src/input.h index 1f0b6ad8..4a850202 100644 --- a/src/input.h +++ b/src/input.h @@ -119,6 +119,7 @@ typedef enum input_backend typedef struct input_driver { + uint8_t slot; input_type_t type; input_backend_t backend; uint8_t _data[CFG_TUH_XINPUT_EPIN_BUFSIZE]; diff --git a/src/lib/xinput_host.c b/src/lib/xinput_host.c index 2daa85d7..304d909a 100644 --- a/src/lib/xinput_host.c +++ b/src/lib/xinput_host.c @@ -117,7 +117,7 @@ bool tuh_xinput_set_rumble(uint8_t dev_addr, uint8_t instance, uint8_t lValue, u memcpy(txbuf, xbox360w_rumble, sizeof(xbox360w_rumble)); txbuf[5] = lValue; txbuf[6] = rValue; - len = sizeof(xbox360w_led); + len = sizeof(xbox360w_rumble); break; case XBOX360_WIRED: memcpy(txbuf, xbox360_wired_rumble, sizeof(xbox360_wired_rumble)); @@ -231,14 +231,13 @@ bool xinputh_set_config(uint8_t dev_addr, uint8_t itf_num) { uint8_t instance = get_instance_id_by_itfnum(dev_addr, itf_num); xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); + xid_itf->connected = true; if (xid_itf->type == XBOX360_WIRELESS) { - tuh_xinput_send_report(dev_addr, instance, xbox360w_controller_info, sizeof(xbox360w_controller_info)); - wait_for_tx_complete(dev_addr, xid_itf->ep_out); - tuh_xinput_send_report(dev_addr, instance, xbox360w_unknown, sizeof(xbox360w_unknown)); - wait_for_tx_complete(dev_addr, xid_itf->ep_out); - tuh_xinput_send_report(dev_addr, instance, xbox360w_rumble_enable, sizeof(xbox360w_rumble_enable)); + //Wireless controllers may not be connected yet. + xid_itf->connected = false; + tuh_xinput_send_report(dev_addr, instance, xbox360w_inquire_present, sizeof(xbox360w_inquire_present)); wait_for_tx_complete(dev_addr, xid_itf->ep_out); } else if (xid_itf->type == XBOX360_WIRED) @@ -273,7 +272,7 @@ bool xinputh_set_config(uint8_t dev_addr, uint8_t itf_num) if (tuh_xinput_mount_cb) { - tuh_xinput_mount_cb(dev_addr, instance, NULL); + tuh_xinput_mount_cb(dev_addr, instance, xid_itf); } return true; } @@ -329,8 +328,62 @@ bool xinputh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, ui pad->sThumbLY = rdata[9] << 8 | rdata[8]; pad->sThumbRX = rdata[11] << 8 | rdata[10]; pad->sThumbRY = rdata[13] << 8 | rdata[12]; + + xid_itf->new_pad_data = true; } } + else if (xid_itf->type == XBOX360_WIRELESS) + { + //Connect/Disconnect packet + if (rdata[0] & 0x08) + { + if (rdata[1] != 0x00 && xid_itf->connected == false) + { + TU_LOG2("XINPUT: WIRELESS CONTROLLER CONNECTED\n"); + xid_itf->connected = true; + } + else if (rdata[1] == 0x00 && xid_itf->connected == true) + { + TU_LOG2("XINPUT: WIRELESS CONTROLLER DISCONNECTED\n"); + xid_itf->connected = false; + } + } + + //Button status packet + if ((rdata[1] & 1) && rdata[5] == 0x13) + { + tu_memclr(pad, sizeof(xinput_gamepad_t)); + uint16_t wButtons = rdata[7] << 8 | rdata[6]; + + //Map digital buttons + if (wButtons & (1 << 0)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_UP; + if (wButtons & (1 << 1)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; + if (wButtons & (1 << 2)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; + if (wButtons & (1 << 3)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; + if (wButtons & (1 << 4)) pad->wButtons |= XINPUT_GAMEPAD_START; + if (wButtons & (1 << 5)) pad->wButtons |= XINPUT_GAMEPAD_BACK; + if (wButtons & (1 << 6)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; + if (wButtons & (1 << 7)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; + if (wButtons & (1 << 8)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; + if (wButtons & (1 << 9)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; + if (wButtons & (1 << 12)) pad->wButtons |= XINPUT_GAMEPAD_A; + if (wButtons & (1 << 13)) pad->wButtons |= XINPUT_GAMEPAD_B; + if (wButtons & (1 << 14)) pad->wButtons |= XINPUT_GAMEPAD_X; + if (wButtons & (1 << 15)) pad->wButtons |= XINPUT_GAMEPAD_Y; + + //Map the left and right triggers + pad->bLeftTrigger = rdata[8]; + pad->bRightTrigger = rdata[9]; + + //Map analog sticks + pad->sThumbLX = rdata[11] << 8 | rdata[10]; + pad->sThumbLY = rdata[13] << 8 | rdata[12]; + pad->sThumbRX = rdata[15] << 8 | rdata[14]; + pad->sThumbRY = rdata[17] << 8 | rdata[16]; + + xid_itf->new_pad_data = true; + } + } else if (xid_itf->type == XBOXONE) { if (rdata[0] == 0x20) @@ -363,6 +416,8 @@ bool xinputh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, ui pad->sThumbLY = rdata[13] << 8 | rdata[12]; pad->sThumbRX = rdata[15] << 8 | rdata[14]; pad->sThumbRY = rdata[17] << 8 | rdata[16]; + + xid_itf->new_pad_data = true; } } else if (xid_itf->type == XBOXOG) @@ -398,9 +453,12 @@ bool xinputh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, ui pad->sThumbLY = rdata[15] << 8 | rdata[14]; pad->sThumbRX = rdata[17] << 8 | rdata[16]; pad->sThumbRY = rdata[19] << 8 | rdata[18]; + + xid_itf->new_pad_data = true; } } - tuh_xinput_report_received_cb(dev_addr, instance, (const uint8_t *)&xid_itf->pad, sizeof(xinput_gamepad_t)); + tuh_xinput_report_received_cb(dev_addr, instance, (const uint8_t *)xid_itf, sizeof(xinputh_interface_t)); + xid_itf->new_pad_data = false; } else { @@ -409,7 +467,6 @@ bool xinputh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, ui tuh_xinput_report_sent_cb(dev_addr, instance, xid_itf->epout_buf, xferred_bytes); } } - return true; } diff --git a/src/lib/xinput_host.h b/src/lib/xinput_host.h index 64ed7d0e..489b10f1 100644 --- a/src/lib/xinput_host.h +++ b/src/lib/xinput_host.h @@ -62,6 +62,8 @@ typedef struct { xinput_type_t type; xinput_gamepad_t pad; + uint8_t connected; + uint8_t new_pad_data; uint8_t itf_num; uint8_t ep_in; uint8_t ep_out; @@ -76,7 +78,7 @@ typedef struct void tuh_xinput_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); TU_ATTR_WEAK void tuh_xinput_report_sent_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); TU_ATTR_WEAK void tuh_xinput_umount_cb(uint8_t dev_addr, uint8_t instance); -TU_ATTR_WEAK void tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, const tusb_desc_interface_t *desc_report); +TU_ATTR_WEAK void tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, const xinputh_interface_t *xinput_itf); bool tuh_xinput_receive_report(uint8_t dev_addr, uint8_t instance); bool tuh_xinput_send_report(uint8_t dev_addr, uint8_t instance, const uint8_t *txbuf, uint16_t len); bool tuh_xinput_set_led(uint8_t dev_addr, uint8_t instance, uint8_t quadrant, bool block); @@ -107,7 +109,7 @@ static const uint8_t xboxone_rumble[] = {0x09, 0x00, 0x00, 0x09, 0x00, 0x0f, 0x0 static const uint8_t xbox360w_led[] = {0x00, 0x00, 0x08, 0x40}; //Sending 0x00, 0x00, 0x08, 0x00 will permanently disable rumble until you do this: static const uint8_t xbox360w_rumble_enable[] = {0x00, 0x00, 0x08, 0x01}; -static const uint8_t xbox360w_rumble[] = {0x00, 0x01, 0x0F, 0xC0}; +static const uint8_t xbox360w_rumble[] = {0x00, 0x01, 0x0F, 0xC0, 0x00, 0x00}; static const uint8_t xbox360w_inquire_present[] = {0x08, 0x00, 0x0F, 0xC0}; static const uint8_t xbox360w_controller_info[] = {0x00, 0x00, 0x00, 0x40}; static const uint8_t xbox360w_unknown[] = {0x00, 0x00, 0x02, 0x80}; From c993a61911ffa54549a9225dca4c72495a2322a8 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 11 Jan 2022 12:03:14 +1030 Subject: [PATCH 093/121] TinyUSB: Update submodule --- src/lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tinyusb b/src/lib/tinyusb index 790466c7..848be4be 160000 --- a/src/lib/tinyusb +++ b/src/lib/tinyusb @@ -1 +1 @@ -Subproject commit 790466c757df336b89a299682a6825fae3b4da90 +Subproject commit 848be4be1f4806b860f1917a1e1ec1ad8abec0d0 From 6cd69d8c2cb52745eea2db5eee923a1f55c4cfd3 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 11 Jan 2022 13:50:52 +1030 Subject: [PATCH 094/121] TinyUSB: Update submodule --- src/lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tinyusb b/src/lib/tinyusb index 848be4be..b4d1216a 160000 --- a/src/lib/tinyusb +++ b/src/lib/tinyusb @@ -1 +1 @@ -Subproject commit 848be4be1f4806b860f1917a1e1ec1ad8abec0d0 +Subproject commit b4d1216ae46e95753047850ad8e30fbbd8851a12 From e224a71653106a9c986711df283b3d30b29eca64 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Wed, 12 Jan 2022 17:30:37 +1030 Subject: [PATCH 095/121] Input: Add HID mouse input driver --- src/input.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib/hid_host.c | 36 ------------------------ 2 files changed, 68 insertions(+), 36 deletions(-) delete mode 100644 src/lib/hid_host.c diff --git a/src/input.cpp b/src/input.cpp index ec44b4b7..54f81ebb 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -35,6 +35,52 @@ static input_driver_t *find_slot(uint16_t uid) return NULL; } +void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) +{ + uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); + + if (itf_protocol != HID_ITF_PROTOCOL_NONE) + { + input_driver_t *in_dev = find_slot(0); + + in_dev->type = (itf_protocol == HID_ITF_PROTOCOL_MOUSE) ? INPUT_MOUSE : INPUT_KEYBOARD; + in_dev->backend = (itf_protocol == HID_ITF_PROTOCOL_MOUSE) ? BACKEND_HID_MOUSE : BACKEND_HID_KEYBOARD; + in_dev->uid = dev_addr << 8 | instance; + in_dev->set_rumble = NULL; + in_dev->set_led = NULL; + in_dev->data = in_dev->_data; + + tuh_hid_receive_report(dev_addr, instance); + } +} + +// Invoked when received report from device via interrupt endpoint +static uint32_t hid_data_tick[MAX_USB_CONTROLLERS] = {0}; +void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) +{ + uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); + input_driver_t *in_dev = find_slot(dev_addr << 8 | instance); + + if (in_dev != NULL && itf_protocol != HID_ITF_PROTOCOL_NONE) + { + hid_data_tick[in_dev->slot] = n64hal_millis(); + memcpy(in_dev->data, report, TU_MIN(len, CFG_TUH_XINPUT_EPIN_BUFSIZE)); + } + + tuh_hid_receive_report(dev_addr, instance); +} + +void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) +{ + uint16_t uid = dev_addr << 8 | instance; + input_driver_t *in_dev = find_slot(uid); + while (in_dev != NULL) + { + memset(in_dev, 0, sizeof(input_driver_t)); + in_dev = find_slot(uid); + } +} + void tuh_xinput_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { xinputh_interface_t *xid_itf = (xinputh_interface_t *)report; @@ -214,6 +260,28 @@ uint16_t input_get_state(uint8_t id, void *response, bool *combo_pressed) state->dButtons |= N64_RES; } } + else if (input_is(id, INPUT_MOUSE)) + { + //N64 report is basically a n64 controller response + n64_buttonmap *state = (n64_buttonmap *)response; + hid_mouse_report_t *report = (hid_mouse_report_t *)in_dev->data; + bool new_data = state->x_axis != report->x || state->y_axis != -report->y; + + state->dButtons = 0; + state->x_axis = report->x; + state->y_axis = -report->y; + + if (report->buttons & (1 << 0)) state->dButtons |= N64_A; //A left click + if (report->buttons & (1 << 1)) state->dButtons |= N64_B; //B right click + if (report->buttons & (1 << 2)) state->dButtons |= N64_ST; //ST middle click + + //Need to do this for stale data and mouse wont send a 0 byte if its not moving + if (n64hal_millis() - hid_data_tick[in_dev->slot] > 10) + { + report->x = 0; + report->y = 0; + } + } return 1; } diff --git a/src/lib/hid_host.c b/src/lib/hid_host.c deleted file mode 100644 index 01e0fd79..00000000 --- a/src/lib/hid_host.c +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#include "tusb_option.h" - -#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HID) - -#include "host/usbh.h" -#include "host/usbh_classdriver.h" -#include "class/hid/hid_host.h" - -// Invoked when device with hid interface is mounted -// Report descriptor is also available for use. tuh_hid_parse_report_descriptor() -// can be used to parse common/simple enough descriptor. -// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped -// therefore report_desc = NULL, desc_len = 0 -void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) -{ - uint16_t vid, pid; - tuh_vid_pid_get(dev_addr, &vid, &pid); - - TU_LOG2("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance); - TU_LOG2("VID = %04x, PID = %04x\r\n", vid, pid); -} - -// Invoked when received report from device via interrupt endpoint -void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len) -{ - // continue to request to receive report - if ( !tuh_hid_receive_report(dev_addr, instance) ) - { - TU_LOG2("Error: cannot request to receive report\r\n"); - } -} - -#endif \ No newline at end of file From 3b6ff4b66288a94c9d4c3f6c096b29f8b86baeab Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Sat, 15 Jan 2022 19:17:10 +0000 Subject: [PATCH 096/121] Improve CI to upload dev artefacts Rename port_null to port_template to build with CI --- .github/workflows/build.yml | 31 +- platformio.ini | 8 +- .../fileio_null.cpp | 156 ++--- src/{port_null => port_template}/hal_null.cpp | 628 +++++++++--------- .../memory_null.cpp | 100 +-- src/{port_null => port_template}/port_conf.h | 74 +-- src/{port_null => port_template}/tft_null.cpp | 212 +++--- .../usbh_null.cpp | 32 +- 8 files changed, 629 insertions(+), 612 deletions(-) rename src/{port_null => port_template}/fileio_null.cpp (96%) rename src/{port_null => port_template}/hal_null.cpp (96%) rename src/{port_null => port_template}/memory_null.cpp (96%) rename src/{port_null => port_template}/port_conf.h (96%) rename src/{port_null => port_template}/tft_null.cpp (96%) rename src/{port_null => port_template}/usbh_null.cpp (96%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 05a6b26b..9a1d4c0d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,7 @@ on: push: branches: - master + - dev* jobs: build: @@ -16,6 +17,9 @@ jobs: BUILD_TAG: 0 runs-on: ubuntu-latest + strategy: + matrix: + board: [teensy41,template] steps: - name: Checkout repo @@ -31,7 +35,7 @@ jobs: git submodule init hw/mcu/nxp/mcux-sdk git submodule update cd ../../../ - + - name: Set up Python uses: actions/setup-python@v1 @@ -43,9 +47,22 @@ jobs: echo "BUILD_TAG=$BUILD_TAG" >> $GITHUB_ENV - name: Compile code - run: platformio run + run: | + platformio platform update + platformio run -e ${{ matrix.board }} + # platformio system prune --force + + - name: Upload firmware artifact to current run + uses: actions/upload-artifact@v2 + with: + name: test-firmware-${{ matrix.board }} + path: | + .pio/build/**/*.hex + .pio/build/**/*.bin + .pio/build/**/*.elf + .pio/build/**/*.map - - if: github.event_name == 'push' + - if: github.event_name == 'push' && github.ref == 'refs/heads/master' #TODO handle previews name: Create Release id: create_release uses: "actions/create-release@v1" @@ -55,12 +72,12 @@ jobs: draft: false prerelease: false - - if: github.event_name == 'push' - name: Upload binary to release + - if: github.event_name == 'push' && github.ref == 'refs/heads/master' #TODO handle previews + name: Upload binary for release id: upload-release-asset uses: actions/upload-release-asset@v1 with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: .pio/build/teensy41/firmware.hex - asset_name: firmware-teensy41.hex + asset_path: .pio/build/${{ matrix.board }}/firmware.hex + asset_name: firmware-${{ matrix.board }}.hex asset_content_type: application/hex diff --git a/platformio.ini b/platformio.ini index 98fcac8d..729df870 100644 --- a/platformio.ini +++ b/platformio.ini @@ -124,17 +124,17 @@ build_flags = -DUSE_HAL_DRIVER -DSTM32F750xx -[env:null] +[env:template] platform = native src_filter = ${common_env_data.src_filter} - + - + + + + + + build_flags = ${common_env_data.build_flags} - -Isrc/port_null/ + -Isrc/port_template/ -DCFG_TUSB_MCU=OPT_MCU_NONE -lpthread diff --git a/src/port_null/fileio_null.cpp b/src/port_template/fileio_null.cpp similarity index 96% rename from src/port_null/fileio_null.cpp rename to src/port_template/fileio_null.cpp index 6bdee4fc..182f5ac3 100644 --- a/src/port_null/fileio_null.cpp +++ b/src/port_template/fileio_null.cpp @@ -1,78 +1,78 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#include -#include - -/* - * Function: Initliased the File access device (SD Card, EMMC, Flash ROM, etc) - * This is used to save/load mempaks, usb64 config settings, GB Roms for transfer pak etc. - * ---------------------------- - * Returns true on sucess. - */ -bool fileio_dev_init() -{ - return true; -} - -/* - * Function: Opens a directory and returns a handle to it. - * Used in confunction with fileio_dev_get_next_filename()and fileio_dev_close_dir(); - * ---------------------------- - * dir: The directory path to open. "/" should be the root directory. - * Returns handle or 0 on error. - */ -int fileio_dev_open_dir(const char *dir) -{ - return 0; -} - -/* - * Function: Returns the next filename of a file in a directory handle from fileio_dev_open_dir. - * Used in confunction with fileio_dev_open_dir()and fileio_dev_close_dir(); - * ---------------------------- - * handle: The directory handle to get the next file from. - * Returns filename or NULL on error/no more files. - */ -const char *fileio_dev_get_next_filename(int handle) -{ - return NULL; -} - -/* - * Function: Closes a directory handle opened with fileio_dev_open_dir - * Used in confunction with fileio_dev_open_dir() and fileio_dev_get_next_filename(); - * ---------------------------- - * handle: The directory handle to close obtained with fileio_dev_open_dir - * Returns void. - */ -void fileio_dev_close_dir(int handle) -{ -} - -/* - * Function: Reads a file from storage. - * ---------------------------- - * filename: The name of the file to read. - * file_offset: The offset of the file to read from. 0 is the beginning of the file. - * data: Return data buffer - * len: How many bytes to read from file_offset - * Returns -1: Cant open file, -2: Cant read file: 0: Success. - */ -int fileio_dev_read(char *filename, uint32_t file_offset, uint8_t *data, uint32_t len) -{ - return -1; -} - -/* - * Function: Writes a file to storage. This should always create a new file or overwrite if the file exists. - * ---------------------------- - * filename: The name of the file to write. - * data: The data to write - * len: How many bytes to write - * Returns -1: Cant open file, -2: Cant read file: 0: Success. - */ -int fileio_dev_write(char *filename, uint8_t *data, uint32_t len) -{ - return -1; -} +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include + +/* + * Function: Initliased the File access device (SD Card, EMMC, Flash ROM, etc) + * This is used to save/load mempaks, usb64 config settings, GB Roms for transfer pak etc. + * ---------------------------- + * Returns true on sucess. + */ +bool fileio_dev_init() +{ + return true; +} + +/* + * Function: Opens a directory and returns a handle to it. + * Used in confunction with fileio_dev_get_next_filename()and fileio_dev_close_dir(); + * ---------------------------- + * dir: The directory path to open. "/" should be the root directory. + * Returns handle or 0 on error. + */ +int fileio_dev_open_dir(const char *dir) +{ + return 0; +} + +/* + * Function: Returns the next filename of a file in a directory handle from fileio_dev_open_dir. + * Used in confunction with fileio_dev_open_dir()and fileio_dev_close_dir(); + * ---------------------------- + * handle: The directory handle to get the next file from. + * Returns filename or NULL on error/no more files. + */ +const char *fileio_dev_get_next_filename(int handle) +{ + return NULL; +} + +/* + * Function: Closes a directory handle opened with fileio_dev_open_dir + * Used in confunction with fileio_dev_open_dir() and fileio_dev_get_next_filename(); + * ---------------------------- + * handle: The directory handle to close obtained with fileio_dev_open_dir + * Returns void. + */ +void fileio_dev_close_dir(int handle) +{ +} + +/* + * Function: Reads a file from storage. + * ---------------------------- + * filename: The name of the file to read. + * file_offset: The offset of the file to read from. 0 is the beginning of the file. + * data: Return data buffer + * len: How many bytes to read from file_offset + * Returns -1: Cant open file, -2: Cant read file: 0: Success. + */ +int fileio_dev_read(char *filename, uint32_t file_offset, uint8_t *data, uint32_t len) +{ + return -1; +} + +/* + * Function: Writes a file to storage. This should always create a new file or overwrite if the file exists. + * ---------------------------- + * filename: The name of the file to write. + * data: The data to write + * len: How many bytes to write + * Returns -1: Cant open file, -2: Cant read file: 0: Success. + */ +int fileio_dev_write(char *filename, uint8_t *data, uint32_t len) +{ + return -1; +} diff --git a/src/port_null/hal_null.cpp b/src/port_template/hal_null.cpp similarity index 96% rename from src/port_null/hal_null.cpp rename to src/port_template/hal_null.cpp index 9d31fbb9..e083ce5a 100644 --- a/src/port_null/hal_null.cpp +++ b/src/port_template/hal_null.cpp @@ -1,314 +1,314 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#include -#include "common.h" -#include "memory.h" -#include "fileio.h" -#include "memory.h" - -/* - * Function: Initialse any device specifc aspects - * ---------------------------- - * Returns: void - */ -void n64hal_system_init() -{ -} - -/* - * Function: Initialse the device debuffer (i.e UART etc) - * ---------------------------- - * Returns: void - */ -void n64hal_debug_init() -{ -} - -/* - * Function: Initialse the device GPIO for all pins set in usb64_conf.h - * Note, n64 controller pins must be input pullup wth falling edge interrupt enabled. - * ---------------------------- - * Returns: void - */ -void n64hal_gpio_init() -{ -} - -/* - * Function: Write a character to a debug output (i.e UART etc) - * ---------------------------- - * Returns: void - */ -void n64hal_debug_write(char c) -{ -} - -/* - * Function: Disable global interrupts for the device. - * ---------------------------- - * Returns: void - */ -void n64hal_disable_interrupts() -{ -} - -/* - * Function: Enable global interrupts for the device. - * ---------------------------- - * Returns: void - */ -void n64hal_enable_interrupts() -{ -} - -/* - * Function: Attach an interrupt from a pin (See usb64_conf.h for pin numbers) - * ---------------------------- - * Returns: void - * - * pin: The pin the configure (See usb64_conf.h) - * handler: Interrupt handler function in the form `void my_int_handler(void)` - * mode: N64_INTMODE_FALLING or N64_INTMODE_CHANGE or N64_INTMODE_RISING - */ -void n64hal_attach_interrupt(usb64_pin_t pin, void (*handler)(void), int mode) -{ -} - -/* - * Function: Disconnect an interrupt from a pin (See usb64_conf.h for pin numbers) - * ---------------------------- - * Returns: void - * - * pin: The pin the configure (See usb64_conf.h) - */ -void n64hal_detach_interrupt(usb64_pin_t pin) -{ -} - -/* - * Function: Reads a hardware realtime clock and populates day,h,m,s. - * Used by Pokemon Gameboy games only with TPAK that have a RTC. - * ---------------------------- - * Returns void - * - * day_high: Bit 0 Most significant bit of Day Counter (Bit 8) - * Bit 6 Halt (0=Active, 1=Stop Timer) - * Bit 7 Day Counter Carry Bit (1=Counter Overflow) - * day_low: Lower 8 bits of Day Counter (0-255) - * h: Pointer to an hour value (0-23) - * m: Pointer to a minute value (0-59) - * s: Pointer to a second value (0-59) - */ -void n64hal_rtc_read(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s) -{ - //Not implemented -} - -/* - * Function: Writes to a hardware realtime clock with day,h,m,s,dst - * Used by Pokemon Gameboy games only with TPAK that have a RTC. - * ---------------------------- - * Returns void - * - * day_high: Bit 0 Most significant bit of Day Counter (Bit 8) - * Bit 6 Halt (0=Active, 1=Stop Timer) - * Bit 7 Day Counter Carry Bit (1=Counter Overflow) - * day_low: Lower 8 bits of Day Counter (0-255) - * h: Pointer to an hour value (0-23) - * m: Pointer to a minute value (0-59) - * s: Pointer to a second value (0-59) - */ -void n64hal_rtc_write(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s) -{ - //Not implemented -} - -/* - * Function: Enable a high speed clock (>20Mhz or so) which is used for low level accurate timings. - * Timer range should be atleast 32-bit. - * Not speed critical - * ---------------------------- - * Returns: Void - */ -void n64hal_hs_tick_init() -{ -} - -/* - * Function: Returns to clock rate of the high speed clock in Hz. - * Speed critical! - * ---------------------------- - * Returns: The rate of the high speed clock in Hz - */ -uint32_t n64hal_hs_tick_get_speed() -{ - return 0; -} - -/* - * Function: Get the current value of the high speed clock. - * Speed critical! - * ---------------------------- - * Returns: A timer count that should run fairly fast (>20Mhz or so) - */ -uint32_t n64hal_hs_tick_get() -{ - return 0; -} - -/* - * Function: Get the number of milliseconds since power up. - * ---------------------------- - * Returns: 32 bit tick value at 1000Hz. - */ -uint32_t n64hal_millis() -{ - return 0; -} - -/* - * Function: Flips the gpio pin direction from an output (driven low) to an input (pulled up) - * for the controller passed by controller. - * Speed critical! - * ---------------------------- - * Returns: void - * - * controller: Pointer to the n64 controller struct which contains the gpio mapping - * val: N64_OUTPUT or N64_INPUT - */ -void n64hal_input_swap(usb64_pin_t pin, uint8_t val) -{ -} - -/* - * Function: Returns the data line level for the pin passed to this function. - * Speed critical! - * ---------------------------- - * Returns: 1 of the line if high, or 0 if the line is low. - * - * pin: The pin the configure (See usb64_conf.h) - */ -uint8_t n64hal_input_read(usb64_pin_t pin) -{ - return 0; -} - -/* - * Function: Sets an output GPI to a level - * Speed critical! - * ---------------------------- - * Returns: void. - * - * pin: The pin the configure (See usb64_conf.h) - * level: 1 or 0 - */ -void n64hal_output_set(usb64_pin_t pin, uint8_t level) -{ -} - -/* - * Function: Returns an array of data read from external ram. - * ---------------------------- - * Returns: void - * - * rx_buff: The buffer the returned data will be stored - * src: Pointer to the base address of the source data. - * offset: Bytes from the base address the actual data is we need. - * len: How many bytes to read. - */ -void n64hal_read_extram(void *rx_buff, void *src, uint32_t offset, uint32_t len) -{ - memcpy(rx_buff, (void *)((uintptr_t)src + offset), len); -} - -/* - * Function: Writes an array of data read to external ram. - * ---------------------------- - * Returns: void - * - * tx_buff: The buffer of data to write - * dst: Pointer to the base address of the destination data. - * offset: Bytes from the base address where we need to write. - * len: How many bytes to write. - */ -void n64hal_write_extram(void *tx_buff, void *dst, uint32_t offset, uint32_t len) -{ - memcpy((void *)((uintptr_t)dst + offset), tx_buff, len); - memory_mark_dirty(dst); -} - -/* - * Function: Allocates a block of memory - * ---------------------------- - * Returns: pointer to memory region - * - * len: How many bytes to allocate - */ -void *n64hal_malloc(uint32_t len) -{ - return memory_dev_malloc(len); -} - -/* - * Function: Free a block of memory - * ---------------------------- - * addr: The address to free - */ -void n64hal_free(void *addr) -{ - memory_dev_free(addr); -} - -/* - * Function: Returns a list of gameboy roms located on nonvolatile storage - * WARNING: This mallocs memory on the heap. It must be free'd by user. - * ---------------------------- - * Returns: Number of roms found - * - * gb_list: A list of char pointers to populate - * max: Max number of roms to return - */ -uint32_t n64hal_list_gb_roms(char **gb_list, uint32_t max) -{ - //Retrieve full directory list - char *file_list[256]; - uint32_t num_files = fileio_list_directory(file_list, 256); - - //Find only files with .gb or gbc extensions to populate rom list. - uint32_t rom_count = 0; - for (uint32_t i = 0; i < num_files; i++) - { - if (file_list[i] == NULL) - continue; - - if (strstr(file_list[i], ".GB\0") != NULL || strstr(file_list[i], ".GBC\0") != NULL || - strstr(file_list[i], ".gb\0") != NULL || strstr(file_list[i], ".gbc\0") != NULL) - { - if (rom_count < max) - { - gb_list[rom_count] = (char *)memory_dev_malloc(strlen(file_list[i]) + 1); - strcpy(gb_list[rom_count], file_list[i]); - rom_count++; - } - } - //Free file list as we go - memory_dev_free(file_list[i]); - } - return rom_count; -} - -/* - * Function: Reads data from unbuffered memory. (i.e SD card) - * ---------------------------- - * Returns: Number of roms found - * - * name: Name of file - * file_offset: Located to start reading file - * data: buffer to put data in - * len: number of bytes t0 read. - */ -void n64hal_read_storage(char *name, uint32_t file_offset, uint8_t *data, uint32_t len) -{ - fileio_read_from_file(name, file_offset, data, len); -} +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include "common.h" +#include "memory.h" +#include "fileio.h" +#include "memory.h" + +/* + * Function: Initialse any device specifc aspects + * ---------------------------- + * Returns: void + */ +void n64hal_system_init() +{ +} + +/* + * Function: Initialse the device debuffer (i.e UART etc) + * ---------------------------- + * Returns: void + */ +void n64hal_debug_init() +{ +} + +/* + * Function: Initialse the device GPIO for all pins set in usb64_conf.h + * Note, n64 controller pins must be input pullup wth falling edge interrupt enabled. + * ---------------------------- + * Returns: void + */ +void n64hal_gpio_init() +{ +} + +/* + * Function: Write a character to a debug output (i.e UART etc) + * ---------------------------- + * Returns: void + */ +void n64hal_debug_write(char c) +{ +} + +/* + * Function: Disable global interrupts for the device. + * ---------------------------- + * Returns: void + */ +void n64hal_disable_interrupts() +{ +} + +/* + * Function: Enable global interrupts for the device. + * ---------------------------- + * Returns: void + */ +void n64hal_enable_interrupts() +{ +} + +/* + * Function: Attach an interrupt from a pin (See usb64_conf.h for pin numbers) + * ---------------------------- + * Returns: void + * + * pin: The pin the configure (See usb64_conf.h) + * handler: Interrupt handler function in the form `void my_int_handler(void)` + * mode: N64_INTMODE_FALLING or N64_INTMODE_CHANGE or N64_INTMODE_RISING + */ +void n64hal_attach_interrupt(usb64_pin_t pin, void (*handler)(void), int mode) +{ +} + +/* + * Function: Disconnect an interrupt from a pin (See usb64_conf.h for pin numbers) + * ---------------------------- + * Returns: void + * + * pin: The pin the configure (See usb64_conf.h) + */ +void n64hal_detach_interrupt(usb64_pin_t pin) +{ +} + +/* + * Function: Reads a hardware realtime clock and populates day,h,m,s. + * Used by Pokemon Gameboy games only with TPAK that have a RTC. + * ---------------------------- + * Returns void + * + * day_high: Bit 0 Most significant bit of Day Counter (Bit 8) + * Bit 6 Halt (0=Active, 1=Stop Timer) + * Bit 7 Day Counter Carry Bit (1=Counter Overflow) + * day_low: Lower 8 bits of Day Counter (0-255) + * h: Pointer to an hour value (0-23) + * m: Pointer to a minute value (0-59) + * s: Pointer to a second value (0-59) + */ +void n64hal_rtc_read(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s) +{ + //Not implemented +} + +/* + * Function: Writes to a hardware realtime clock with day,h,m,s,dst + * Used by Pokemon Gameboy games only with TPAK that have a RTC. + * ---------------------------- + * Returns void + * + * day_high: Bit 0 Most significant bit of Day Counter (Bit 8) + * Bit 6 Halt (0=Active, 1=Stop Timer) + * Bit 7 Day Counter Carry Bit (1=Counter Overflow) + * day_low: Lower 8 bits of Day Counter (0-255) + * h: Pointer to an hour value (0-23) + * m: Pointer to a minute value (0-59) + * s: Pointer to a second value (0-59) + */ +void n64hal_rtc_write(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s) +{ + //Not implemented +} + +/* + * Function: Enable a high speed clock (>20Mhz or so) which is used for low level accurate timings. + * Timer range should be atleast 32-bit. + * Not speed critical + * ---------------------------- + * Returns: Void + */ +void n64hal_hs_tick_init() +{ +} + +/* + * Function: Returns to clock rate of the high speed clock in Hz. + * Speed critical! + * ---------------------------- + * Returns: The rate of the high speed clock in Hz + */ +uint32_t n64hal_hs_tick_get_speed() +{ + return 0; +} + +/* + * Function: Get the current value of the high speed clock. + * Speed critical! + * ---------------------------- + * Returns: A timer count that should run fairly fast (>20Mhz or so) + */ +uint32_t n64hal_hs_tick_get() +{ + return 0; +} + +/* + * Function: Get the number of milliseconds since power up. + * ---------------------------- + * Returns: 32 bit tick value at 1000Hz. + */ +uint32_t n64hal_millis() +{ + return 0; +} + +/* + * Function: Flips the gpio pin direction from an output (driven low) to an input (pulled up) + * for the controller passed by controller. + * Speed critical! + * ---------------------------- + * Returns: void + * + * controller: Pointer to the n64 controller struct which contains the gpio mapping + * val: N64_OUTPUT or N64_INPUT + */ +void n64hal_input_swap(usb64_pin_t pin, uint8_t val) +{ +} + +/* + * Function: Returns the data line level for the pin passed to this function. + * Speed critical! + * ---------------------------- + * Returns: 1 of the line if high, or 0 if the line is low. + * + * pin: The pin the configure (See usb64_conf.h) + */ +uint8_t n64hal_input_read(usb64_pin_t pin) +{ + return 0; +} + +/* + * Function: Sets an output GPI to a level + * Speed critical! + * ---------------------------- + * Returns: void. + * + * pin: The pin the configure (See usb64_conf.h) + * level: 1 or 0 + */ +void n64hal_output_set(usb64_pin_t pin, uint8_t level) +{ +} + +/* + * Function: Returns an array of data read from external ram. + * ---------------------------- + * Returns: void + * + * rx_buff: The buffer the returned data will be stored + * src: Pointer to the base address of the source data. + * offset: Bytes from the base address the actual data is we need. + * len: How many bytes to read. + */ +void n64hal_read_extram(void *rx_buff, void *src, uint32_t offset, uint32_t len) +{ + memcpy(rx_buff, (void *)((uintptr_t)src + offset), len); +} + +/* + * Function: Writes an array of data read to external ram. + * ---------------------------- + * Returns: void + * + * tx_buff: The buffer of data to write + * dst: Pointer to the base address of the destination data. + * offset: Bytes from the base address where we need to write. + * len: How many bytes to write. + */ +void n64hal_write_extram(void *tx_buff, void *dst, uint32_t offset, uint32_t len) +{ + memcpy((void *)((uintptr_t)dst + offset), tx_buff, len); + memory_mark_dirty(dst); +} + +/* + * Function: Allocates a block of memory + * ---------------------------- + * Returns: pointer to memory region + * + * len: How many bytes to allocate + */ +void *n64hal_malloc(uint32_t len) +{ + return memory_dev_malloc(len); +} + +/* + * Function: Free a block of memory + * ---------------------------- + * addr: The address to free + */ +void n64hal_free(void *addr) +{ + memory_dev_free(addr); +} + +/* + * Function: Returns a list of gameboy roms located on nonvolatile storage + * WARNING: This mallocs memory on the heap. It must be free'd by user. + * ---------------------------- + * Returns: Number of roms found + * + * gb_list: A list of char pointers to populate + * max: Max number of roms to return + */ +uint32_t n64hal_list_gb_roms(char **gb_list, uint32_t max) +{ + //Retrieve full directory list + char *file_list[256]; + uint32_t num_files = fileio_list_directory(file_list, 256); + + //Find only files with .gb or gbc extensions to populate rom list. + uint32_t rom_count = 0; + for (uint32_t i = 0; i < num_files; i++) + { + if (file_list[i] == NULL) + continue; + + if (strstr(file_list[i], ".GB\0") != NULL || strstr(file_list[i], ".GBC\0") != NULL || + strstr(file_list[i], ".gb\0") != NULL || strstr(file_list[i], ".gbc\0") != NULL) + { + if (rom_count < max) + { + gb_list[rom_count] = (char *)memory_dev_malloc(strlen(file_list[i]) + 1); + strcpy(gb_list[rom_count], file_list[i]); + rom_count++; + } + } + //Free file list as we go + memory_dev_free(file_list[i]); + } + return rom_count; +} + +/* + * Function: Reads data from unbuffered memory. (i.e SD card) + * ---------------------------- + * Returns: Number of roms found + * + * name: Name of file + * file_offset: Located to start reading file + * data: buffer to put data in + * len: number of bytes t0 read. + */ +void n64hal_read_storage(char *name, uint32_t file_offset, uint8_t *data, uint32_t len) +{ + fileio_read_from_file(name, file_offset, data, len); +} diff --git a/src/port_null/memory_null.cpp b/src/port_template/memory_null.cpp similarity index 96% rename from src/port_null/memory_null.cpp rename to src/port_template/memory_null.cpp index 24400510..af733ce5 100644 --- a/src/port_null/memory_null.cpp +++ b/src/port_template/memory_null.cpp @@ -1,50 +1,50 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#include -#include "memory.h" - -/* - * Function: Initalise memory for device (External RAM etc) - * ---------------------------- - * Returns: true on success, false on error - */ -bool memory_dev_init() -{ - return false; -} - -/* - * Function: Allocate a block of memory. This could be large block if using TPAK emulation. - * This function should use internal or external RAM as required. Freed with memory_dev_free() - * ---------------------------- - * Returns: A pointer to the alloced memory, or NULL on error. - * - * len: How many bytes to allocate. - */ -void *memory_dev_malloc(uint32_t len) -{ - return NULL; -} - -/* - * Function: Free an allocated memory block allocated with memory_dev_malloc(); - * ---------------------------- - * Returns: Void - * - * add: Pointer to the address block to free - */ -void memory_dev_free(void *add) -{ -} - -/* - * Function: Detect the amount of external RAM installed. This prints it to the LCD and a number > 0 is required for TPAK - * emulation. If you device has loads of internal RAM suitable for TPAK emulation (>2MB or so) which you want to use, set this to a non-zero number. - * ---------------------------- - * Returns: How many MB of external RAM is installed. - */ -uint8_t memory_get_ext_ram_size() -{ - return 0; -} +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include "memory.h" + +/* + * Function: Initalise memory for device (External RAM etc) + * ---------------------------- + * Returns: true on success, false on error + */ +bool memory_dev_init() +{ + return false; +} + +/* + * Function: Allocate a block of memory. This could be large block if using TPAK emulation. + * This function should use internal or external RAM as required. Freed with memory_dev_free() + * ---------------------------- + * Returns: A pointer to the alloced memory, or NULL on error. + * + * len: How many bytes to allocate. + */ +void *memory_dev_malloc(uint32_t len) +{ + return NULL; +} + +/* + * Function: Free an allocated memory block allocated with memory_dev_malloc(); + * ---------------------------- + * Returns: Void + * + * add: Pointer to the address block to free + */ +void memory_dev_free(void *add) +{ +} + +/* + * Function: Detect the amount of external RAM installed. This prints it to the LCD and a number > 0 is required for TPAK + * emulation. If you device has loads of internal RAM suitable for TPAK emulation (>2MB or so) which you want to use, set this to a non-zero number. + * ---------------------------- + * Returns: How many MB of external RAM is installed. + */ +uint8_t memory_get_ext_ram_size() +{ + return 0; +} diff --git a/src/port_null/port_conf.h b/src/port_template/port_conf.h similarity index 96% rename from src/port_null/port_conf.h rename to src/port_template/port_conf.h index ab2d05ab..7f6f4e44 100644 --- a/src/port_null/port_conf.h +++ b/src/port_template/port_conf.h @@ -1,37 +1,37 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT -#ifndef _USB64_CONF_h -#define _USB64_CONF_h - -/* PIN MAPPING - Teensy uses an Arduino Backend, we just assign the enum to the Arduino Pin number - USB64_PIN_MAX must be the largest pin number in the list add one*/ -typedef enum { - USER_LED_PIN, - N64_FRAME_PIN, - HW_RUMBLE, - N64_CONSOLE_SENSE_PIN, - N64_CONTROLLER_1_PIN, - N64_CONTROLLER_2_PIN, - N64_CONTROLLER_3_PIN, - N64_CONTROLLER_4_PIN, - USB64_PIN_MAX, -} usb64_pin_t; - -/* TFT DISPLAY */ -#define ENABLE_TFT_DISPLAY 1 -#define TFT_ROTATION 1 //0-3 -#define TFT_WIDTH 320 -#define TFT_HEIGHT 240 -#define TFT_PIXEL_SIZE 2 -#define TFT_USE_FRAMEBUFFER 1 - -/* Optional, to save RAM, define for variables to store in flash only */ -#ifndef PROGMEM -#define PROGMEM -#endif -/* Optional, to save RAM, define for function to store in flash only */ -#ifndef FLASHMEM -#define FLASHMEM -#endif - -#endif +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT +#ifndef _USB64_CONF_h +#define _USB64_CONF_h + +/* PIN MAPPING - Teensy uses an Arduino Backend, we just assign the enum to the Arduino Pin number + USB64_PIN_MAX must be the largest pin number in the list add one*/ +typedef enum { + USER_LED_PIN, + N64_FRAME_PIN, + HW_RUMBLE, + N64_CONSOLE_SENSE_PIN, + N64_CONTROLLER_1_PIN, + N64_CONTROLLER_2_PIN, + N64_CONTROLLER_3_PIN, + N64_CONTROLLER_4_PIN, + USB64_PIN_MAX, +} usb64_pin_t; + +/* TFT DISPLAY */ +#define ENABLE_TFT_DISPLAY 1 +#define TFT_ROTATION 1 //0-3 +#define TFT_WIDTH 320 +#define TFT_HEIGHT 240 +#define TFT_PIXEL_SIZE 2 +#define TFT_USE_FRAMEBUFFER 1 + +/* Optional, to save RAM, define for variables to store in flash only */ +#ifndef PROGMEM +#define PROGMEM +#endif +/* Optional, to save RAM, define for function to store in flash only */ +#ifndef FLASHMEM +#define FLASHMEM +#endif + +#endif diff --git a/src/port_null/tft_null.cpp b/src/port_template/tft_null.cpp similarity index 96% rename from src/port_null/tft_null.cpp rename to src/port_template/tft_null.cpp index a3b427e3..18d2cbc6 100644 --- a/src/port_null/tft_null.cpp +++ b/src/port_template/tft_null.cpp @@ -1,106 +1,106 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#include -#include "common.h" -#include "controller_icon.h" -#include "usb64_logo.h" -#include "GuiLite.h" - -c_surface *psurface_guilite = NULL; -c_display *pdisplay_guilite = NULL; -#if TFT_USE_FRAMEBUFFER -static uint8_t _framebuffer[TFT_WIDTH * TFT_HEIGHT * TFT_PIXEL_SIZE]; -#else -struct EXTERNAL_GFX_OP my_gfx_op; -#endif - -//Stub for GuiLite. Remove if not required. -extern "C" void delay_ms(unsigned short nms) -{ -} - -static void _tft_assert(const char *file, int line) -{ - debug_print_error("[TFT] Error: Assert in %s on line %d\n", file, line); - while (1) - ; -} - -static void _tft_log_out(const char *log) -{ - debug_print_status(log); -} - -#if TFT_USE_FRAMEBUFFER == 0 -/* - * Function: Draw a pixel to your display at a given coordinate. Required if NOT using a framebuffer - * ---------------------------- - * Returns: Void - * - * x: horizontal pixel position - * y: vertical pixel position - * rgb: RGB888 colour. You can use GL_RGB_32_to_16 to convert to RGB565 if needed. - */ -static void _draw_pixel(int x, int y, unsigned int rgb) -{ - //Device specific pixel draw -} - -/* - * Function: Fill a given rectangle area. Required if NOT using a framebuffer - * ---------------------------- - * Returns: Void - * - * x0,y0: Top left rectangle pixel position - * x1,y1: Bottom right pixel position - * rgb: RGB888 colour. You can use GL_RGB_32_to_16 to convert to RGB565 if needed. - */ -static void _fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) -{ - -} -#endif - -/* - * Function: Start TFT draw. Required if using a framebuffer. This should draw the framebuffer to the screen using DMA or similar. - * ---------------------------- - * Returns: Void - * - * force: If force is true, you must wait for any previous screen updates to finished then update. - */ -void tft_dev_draw(bool force) -{ - //Draw _framebuffer to screen if TFT_USE_FRAMEBUFFER is set. -} - -/* - * Function: Perform any device specific LCD display setup here. - * ---------------------------- - * Returns: Void - */ -void tft_dev_init() -{ -#if TFT_USE_FRAMEBUFFER - static c_surface surface(TFT_WIDTH, TFT_HEIGHT, 2, Z_ORDER_LEVEL_0); - static c_display display(_framebuffer, TFT_WIDTH, TFT_HEIGHT, &surface); - psurface_guilite = &surface; - pdisplay_guilite = &display; -#else - static c_surface_no_fb surface(TFT_WIDTH, TFT_HEIGHT, 2, &my_gfx_op, Z_ORDER_LEVEL_0); - static c_display display(NULL, TFT_WIDTH, TFT_HEIGHT, &surface); - my_gfx_op.draw_pixel = _draw_pixel; - my_gfx_op.fill_rect = _fill_rect; -#endif - psurface_guilite = &surface; - pdisplay_guilite = &display; - register_debug_function(_tft_assert, _tft_log_out); -#if (ENABLE_TFT_DISPLAY >= 1) - //Device specific init here -#endif -} - -bool tft_dev_is_busy() -{ - return 0; -} +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include "common.h" +#include "controller_icon.h" +#include "usb64_logo.h" +#include "GuiLite.h" + +c_surface *psurface_guilite = NULL; +c_display *pdisplay_guilite = NULL; +#if TFT_USE_FRAMEBUFFER +static uint8_t _framebuffer[TFT_WIDTH * TFT_HEIGHT * TFT_PIXEL_SIZE]; +#else +struct EXTERNAL_GFX_OP my_gfx_op; +#endif + +//Stub for GuiLite. Remove if not required. +extern "C" void delay_ms(unsigned short nms) +{ +} + +static void _tft_assert(const char *file, int line) +{ + debug_print_error("[TFT] Error: Assert in %s on line %d\n", file, line); + while (1) + ; +} + +static void _tft_log_out(const char *log) +{ + debug_print_status(log); +} + +#if TFT_USE_FRAMEBUFFER == 0 +/* + * Function: Draw a pixel to your display at a given coordinate. Required if NOT using a framebuffer + * ---------------------------- + * Returns: Void + * + * x: horizontal pixel position + * y: vertical pixel position + * rgb: RGB888 colour. You can use GL_RGB_32_to_16 to convert to RGB565 if needed. + */ +static void _draw_pixel(int x, int y, unsigned int rgb) +{ + //Device specific pixel draw +} + +/* + * Function: Fill a given rectangle area. Required if NOT using a framebuffer + * ---------------------------- + * Returns: Void + * + * x0,y0: Top left rectangle pixel position + * x1,y1: Bottom right pixel position + * rgb: RGB888 colour. You can use GL_RGB_32_to_16 to convert to RGB565 if needed. + */ +static void _fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) +{ + +} +#endif + +/* + * Function: Start TFT draw. Required if using a framebuffer. This should draw the framebuffer to the screen using DMA or similar. + * ---------------------------- + * Returns: Void + * + * force: If force is true, you must wait for any previous screen updates to finished then update. + */ +void tft_dev_draw(bool force) +{ + //Draw _framebuffer to screen if TFT_USE_FRAMEBUFFER is set. +} + +/* + * Function: Perform any device specific LCD display setup here. + * ---------------------------- + * Returns: Void + */ +void tft_dev_init() +{ +#if TFT_USE_FRAMEBUFFER + static c_surface surface(TFT_WIDTH, TFT_HEIGHT, 2, Z_ORDER_LEVEL_0); + static c_display display(_framebuffer, TFT_WIDTH, TFT_HEIGHT, &surface); + psurface_guilite = &surface; + pdisplay_guilite = &display; +#else + static c_surface_no_fb surface(TFT_WIDTH, TFT_HEIGHT, 2, &my_gfx_op, Z_ORDER_LEVEL_0); + static c_display display(NULL, TFT_WIDTH, TFT_HEIGHT, &surface); + my_gfx_op.draw_pixel = _draw_pixel; + my_gfx_op.fill_rect = _fill_rect; +#endif + psurface_guilite = &surface; + pdisplay_guilite = &display; + register_debug_function(_tft_assert, _tft_log_out); +#if (ENABLE_TFT_DISPLAY >= 1) + //Device specific init here +#endif +} + +bool tft_dev_is_busy() +{ + return 0; +} diff --git a/src/port_null/usbh_null.cpp b/src/port_template/usbh_null.cpp similarity index 96% rename from src/port_null/usbh_null.cpp rename to src/port_template/usbh_null.cpp index 582e8539..79443d1a 100644 --- a/src/port_null/usbh_null.cpp +++ b/src/port_template/usbh_null.cpp @@ -1,16 +1,16 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#include "tusb.h" - -void USB_IRQHandler(void) -{ - tuh_int_handler(0); -} - -void usbh_dev_init() -{ - //Device specific usb host hardware init. - //Look here for some rough guidance https://github.com/hathach/tinyusb/tree/master/hw/bsp - //Normally need to init hardware registers and USB clocks and hook the device USB IRQ to `USB_IRQHandler`. -} +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include "tusb.h" + +void USB_IRQHandler(void) +{ + tuh_int_handler(0); +} + +void usbh_dev_init() +{ + //Device specific usb host hardware init. + //Look here for some rough guidance https://github.com/hathach/tinyusb/tree/master/hw/bsp + //Normally need to init hardware registers and USB clocks and hook the device USB IRQ to `USB_IRQHandler`. +} From 820506dd1abd846fe4315fb50b4a66700faf4ebe Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sun, 9 Jan 2022 17:42:48 +1030 Subject: [PATCH 097/121] usb64: Add stm32f769i-dk environment --- platformio.ini | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/platformio.ini b/platformio.ini index 729df870..c1a23aed 100644 --- a/platformio.ini +++ b/platformio.ini @@ -124,6 +124,31 @@ build_flags = -DUSE_HAL_DRIVER -DSTM32F750xx +[env:disco_f769ni] +platform = ststm32 +board = disco_f769ni +framework = stm32cube +board_build.ldscript = src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld + +src_filter = + ${common_env_data.src_filter} + + + + + + + + + + + + + +build_flags = + ${common_env_data.build_flags} + -Isrc/port_stm32f7/stm37f769-dk + -Isrc/port_stm32f7/common/fatfs + -Isrc/port_stm32f7/common/fatfs/drivers + -Isrc/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery + -DCFG_TUSB_MCU=OPT_MCU_STM32F7 + -DAPPLICATION_ADDRESS=0x8000000U ;Entry point is internal FLASH. + -DUSE_HAL_DRIVER + [env:template] platform = native From b30e231ecdd307116dd7efc3691ccb1237b1b4ee Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sun, 9 Jan 2022 17:43:05 +1030 Subject: [PATCH 098/121] STM32F769i: Initial commit --- .../stm37f769-dk/STM32F769NIHX_FLASH.ld | 187 +++++++ .../stm37f769-dk/fileio_stm32.cpp | 138 +++++ src/port_stm32f7/stm37f769-dk/hal_stm32.cpp | 527 ++++++++++++++++++ src/port_stm32f7/stm37f769-dk/main.h | 377 +++++++++++++ .../stm37f769-dk/memory_stm32.cpp | 71 +++ src/port_stm32f7/stm37f769-dk/port_conf.h | 71 +++ src/port_stm32f7/stm37f769-dk/tft_stm32.cpp | 88 +++ src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp | 44 ++ 8 files changed, 1503 insertions(+) create mode 100644 src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld create mode 100644 src/port_stm32f7/stm37f769-dk/fileio_stm32.cpp create mode 100644 src/port_stm32f7/stm37f769-dk/hal_stm32.cpp create mode 100644 src/port_stm32f7/stm37f769-dk/main.h create mode 100644 src/port_stm32f7/stm37f769-dk/memory_stm32.cpp create mode 100644 src/port_stm32f7/stm37f769-dk/port_conf.h create mode 100644 src/port_stm32f7/stm37f769-dk/tft_stm32.cpp create mode 100644 src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp diff --git a/src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld b/src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld new file mode 100644 index 00000000..b6ecbfee --- /dev/null +++ b/src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld @@ -0,0 +1,187 @@ +/* +****************************************************************************** +** +** @file : LinkerScript.ld +** +** @author : Auto-generated by STM32CubeIDE +** +** Abstract : Linker script for STM32F769I-DISCO Board embedding STM32F769NIHx Device from stm32f7 series +** 2048Kbytes FLASH +** 512Kbytes RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used +** +** Target : STMicroelectronics STM32 +** +** Distribution: The file is distributed as is, without any warranty +** of any kind. +** +****************************************************************************** +** @attention +** +**

© Copyright (c) 2022 STMicroelectronics. +** All rights reserved.

+** +** This software component is licensed by ST under BSD 3-Clause license, +** the "License"; You may not use this file except in compliance with the +** License. You may obtain a copy of the License at: +** opensource.org/licenses/BSD-3-Clause +** +****************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ + +_Min_Heap_Size = 0x200; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Memories definition */ +MEMORY +{ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K + FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K +} + +/* Sections */ +SECTIONS +{ + /* The startup code into "FLASH" Rom type memory */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data into "FLASH" Rom type memory */ + .text : + { + . = ALIGN(4); + *(.text.Reset_Handler) /* Reset handler needs to be in flash so its available to copy the other code to RAM */ + *(.text.code) /* Code that can remain in flash (not speed critical. init code etc) */ + *(.text.rodata) /* Read only data that can remain in flash to save RAM */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data into "FLASH" Rom type memory */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { + . = ALIGN(4); + *(.ARM.extab* .gnu.linkonce.armextab.*) + . = ALIGN(4); + } >RAM + + .ARM : { + . = ALIGN(4); + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + . = ALIGN(4); + } >RAM + + .preinit_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + . = ALIGN(4); + } >FLASH + + .init_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + . = ALIGN(4); + } >FLASH + + .fini_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(4); + } >FLASH + + /* Used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections into "RAM" Ram type memory */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + + } >RAM AT> FLASH + + /* Uninitialized data section into "RAM" Ram type memory */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM + + /* Remove information from the compiler libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/src/port_stm32f7/stm37f769-dk/fileio_stm32.cpp b/src/port_stm32f7/stm37f769-dk/fileio_stm32.cpp new file mode 100644 index 00000000..a3e43a7b --- /dev/null +++ b/src/port_stm32f7/stm37f769-dk/fileio_stm32.cpp @@ -0,0 +1,138 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include "common.h" +#include "ff.h" +#include "ff_gen_drv.h" +#include "sd_diskio.h" + +static FATFS fs; +static char SDPath[4] = {0}; +extern const Diskio_drvTypeDef SD_Driver; + +bool fileio_dev_init() +{ + if (FATFS_LinkDriver(&SD_Driver, SDPath) != 0) + { + return false; + } + + int retries = 3; + + while (retries) + { + if (f_mount(&fs, (TCHAR const *)SDPath, 1) != FR_OK) + { + retries--; + if (retries == 0) + return false; + HAL_Delay(100); + } + else + { + break; + } + } + + return f_chdir((TCHAR const *)SDPath) == FR_OK; +} + +int fileio_dev_open_dir(const char *dir) +{ + DIR *dp = (DIR *)malloc(sizeof(DIR)); + if (dp == NULL) + { + return 0; + } + n64hal_disable_interrupts(); + FRESULT res = f_opendir(dp, (const TCHAR *)dir); + n64hal_enable_interrupts(); + + if (res != FR_OK) + { + free(dp); + return 0; + } + + return (uint32_t)dp; +} + +const char *fileio_dev_get_next_filename(int handle) +{ + static FILINFO fno; + FRESULT res; + DIR *dp = (DIR *)handle; + n64hal_disable_interrupts(); + res = f_readdir(dp, &fno); + n64hal_enable_interrupts(); + if (dp && res == FR_OK && fno.fname[0] != 0) + { + return fno.fname; + } + return NULL; +} + +void fileio_dev_close_dir(int handle) +{ + if (handle == 0) + { + return; + } + + DIR *dp = (DIR *)handle; + f_closedir(dp); + free(dp); +} + +int fileio_dev_read(char *filename, uint32_t file_offset, uint8_t *data, uint32_t len) +{ + FIL fil; + FRESULT res; + UINT br; + n64hal_disable_interrupts(); + res = f_open(&fil, filename, FA_READ); + if (res != FR_OK) + { + n64hal_enable_interrupts(); + return -1; + } + + f_lseek(&fil, file_offset); + res = f_read(&fil, data, len, &br); + if (res != FR_OK || br != len) + { + f_close(&fil); + n64hal_enable_interrupts(); + return -2; + } + + f_close(&fil); + n64hal_enable_interrupts(); + return 0; +} + +int fileio_dev_write(char *filename, uint8_t *data, uint32_t len) +{ + FIL fil; + FRESULT res; + UINT bw; + n64hal_disable_interrupts(); + res = f_open(&fil, filename, FA_WRITE | FA_CREATE_ALWAYS); + if (res != FR_OK) + { + n64hal_enable_interrupts(); + return -1; + } + + res = f_write(&fil, data, len, &bw); + if (res != FR_OK || bw != len) + { + f_close(&fil); + n64hal_enable_interrupts(); + return -2; + } + + f_close(&fil); + n64hal_enable_interrupts(); + return 0; +} diff --git a/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp b/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp new file mode 100644 index 00000000..763b9c8c --- /dev/null +++ b/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp @@ -0,0 +1,527 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include +#include "common.h" +#include "memory.h" +#include "fileio.h" +#include "memory.h" + +UART_HandleTypeDef huart6; +CRC_HandleTypeDef hcrc; + +static void SystemClock_Config(void); + +//usb64 passes a pin number to the backend (See port_conf.h). We need to convert this usb64 pin number to a +//port and device pin number. +typedef struct +{ + uint16_t pin; + GPIO_TypeDef *port; +} dev_gpio_t; + +static dev_gpio_t _dev_gpio[USB64_PIN_MAX]; +static dev_gpio_t *n64hal_pin_to_gpio(usb64_pin_t pin) +{ + if (pin == -1 || pin >= USB64_PIN_MAX) + { + return NULL; + } + return &_dev_gpio[pin]; +} + +//n64 controller interrupt handles +void (*n64_1)(void) = NULL; +void (*n64_2)(void) = NULL; +void (*n64_3)(void) = NULL; +void (*n64_4)(void) = NULL; + +void n64hal_system_init() +{ + SCB_EnableICache(); + SCB_EnableDCache(); + + HAL_Init(); + SystemClock_Config(); + + __disable_irq(); + //Move the interrupt vector table from Flash to RAM. Should have better interrupt perf and consistency + void *vtor = (void *)RAMDTCM_BASE; + memcpy(vtor, (void *)SCB->VTOR, 0x200); + SCB->VTOR = (uint32_t)vtor; + __enable_irq(); + + __HAL_RCC_CRC_CLK_ENABLE(); + hcrc.Instance = CRC; + hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE; + hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE; + hcrc.Init.GeneratingPolynomial = 0x85; + hcrc.Init.CRCLength = CRC_POLYLENGTH_8B; + hcrc.Init.InitValue = 0; + hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE; + hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE; + hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES; + HAL_CRC_Init(&hcrc); +} + +void n64hal_debug_init() +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + __HAL_RCC_USART6_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + GPIO_InitStruct.Pin = GPIO_PIN_7 | GPIO_PIN_6; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_USART6; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + huart6.Instance = USART6; + huart6.Init.BaudRate = 115200; + huart6.Init.WordLength = UART_WORDLENGTH_8B; + huart6.Init.StopBits = UART_STOPBITS_1; + huart6.Init.Parity = UART_PARITY_NONE; + huart6.Init.Mode = UART_MODE_TX_RX; + huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart6.Init.OverSampling = UART_OVERSAMPLING_16; + huart6.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; + huart6.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; + HAL_UART_Init(&huart6); +} + +void n64hal_gpio_init() +{ + dev_gpio_t *pin; + GPIO_InitTypeDef GPIO_InitStruct; + + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + + for (int i = 0; i < USB64_PIN_MAX; i++) + { + switch (i) + { + case N64_CONSOLE_SENSE_PIN: + _dev_gpio[i].pin = GPIO_PIN_6; //D3 (PF6) + _dev_gpio[i].port = GPIOF; + break; + case N64_CONTROLLER_1_PIN: + _dev_gpio[i].pin = GPIO_PIN_1; //D2 (PJ1) + _dev_gpio[i].port = GPIOJ; + break; + case N64_CONTROLLER_2_PIN: + _dev_gpio[i].pin = GPIO_PIN_0; //D4 (PJ0) + _dev_gpio[i].port = GPIOJ; + break; + case N64_CONTROLLER_3_PIN: + _dev_gpio[i].pin = GPIO_PIN_3; //D7 (PJ3) + _dev_gpio[i].port = GPIOJ; + break; + case N64_CONTROLLER_4_PIN: + _dev_gpio[i].pin = GPIO_PIN_4; //D8 (PJ4) + _dev_gpio[i].port = GPIOJ; + break; + } + } + + pin = n64hal_pin_to_gpio(N64_CONSOLE_SENSE_PIN); + GPIO_InitStruct.Pin = pin->pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + HAL_GPIO_Init(pin->port, &GPIO_InitStruct); + + pin = n64hal_pin_to_gpio(N64_CONTROLLER_1_PIN); + HAL_GPIO_WritePin(pin->port, pin->pin, GPIO_PIN_RESET); + GPIO_InitStruct.Pin = pin->pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(pin->port, &GPIO_InitStruct); + + pin = n64hal_pin_to_gpio(N64_CONTROLLER_2_PIN); + HAL_GPIO_WritePin(pin->port, pin->pin, GPIO_PIN_RESET); + GPIO_InitStruct.Pin = pin->pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(pin->port, &GPIO_InitStruct); + + pin = n64hal_pin_to_gpio(N64_CONTROLLER_3_PIN); + HAL_GPIO_WritePin(pin->port, pin->pin, GPIO_PIN_RESET); + GPIO_InitStruct.Pin = pin->pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(pin->port, &GPIO_InitStruct); + + pin = n64hal_pin_to_gpio(N64_CONTROLLER_4_PIN); + HAL_GPIO_WritePin(pin->port, pin->pin, GPIO_PIN_RESET); + GPIO_InitStruct.Pin = pin->pin; + GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + HAL_GPIO_Init(pin->port, &GPIO_InitStruct); + + HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(EXTI0_IRQn); + + HAL_NVIC_SetPriority(EXTI1_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(EXTI1_IRQn); + + HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(EXTI3_IRQn); + + HAL_NVIC_SetPriority(EXTI4_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(EXTI4_IRQn); + + NVIC_SetPriority(SysTick_IRQn, 15); +} + +void n64hal_debug_write(char c) +{ + HAL_UART_Transmit(&huart6, (uint8_t *)&c, 1, 5000); +} + +void n64hal_disable_interrupts() +{ + //Disable the controller input interrupts + HAL_NVIC_DisableIRQ(EXTI9_5_IRQn); + HAL_NVIC_DisableIRQ(EXTI2_IRQn); + HAL_NVIC_DisableIRQ(EXTI3_IRQn); + HAL_NVIC_DisableIRQ(OTG_FS_IRQn); +} + +void n64hal_enable_interrupts() +{ + //Disable the controller input interrupts + HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); + HAL_NVIC_EnableIRQ(EXTI2_IRQn); + HAL_NVIC_EnableIRQ(EXTI3_IRQn); + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); +} + +void n64hal_attach_interrupt(usb64_pin_t pin, void (*handler)(void), int mode) +{ + (void)mode; //Should always be falling. Not used currently + switch (pin) + { + case N64_CONTROLLER_1_PIN: + n64_1 = handler; + break; + case N64_CONTROLLER_2_PIN: + n64_2 = handler; + break; + case N64_CONTROLLER_3_PIN: + n64_3 = handler; + break; + case N64_CONTROLLER_4_PIN: + n64_4 = handler; + break; + default: + break; //Not required + } +} + +void n64hal_detach_interrupt(usb64_pin_t pin) +{ + switch (pin) + { + case N64_CONTROLLER_1_PIN: + n64_1 = NULL; + break; + case N64_CONTROLLER_2_PIN: + n64_2 = NULL; + break; + case N64_CONTROLLER_3_PIN: + n64_3 = NULL; + break; + case N64_CONTROLLER_4_PIN: + n64_4 = NULL; + break; + default: + break; //Not required + } +} + +void n64hal_rtc_read(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s) +{ + //Not implemented +} + +void n64hal_rtc_write(uint8_t *day_high, uint8_t *day_low, uint8_t *h, uint8_t *m, uint8_t *s) +{ + //Not implemented +} + +void n64hal_hs_tick_init() +{ + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->LAR = 0xC5ACCE55; + DWT->CYCCNT = 0; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; +} + +uint32_t n64hal_hs_tick_get_speed() +{ + return SystemCoreClock; +} + +uint32_t n64hal_hs_tick_get() +{ + return DWT->CYCCNT; +} + +uint32_t n64hal_millis() +{ + return HAL_GetTick(); +} + +void n64hal_input_swap(usb64_pin_t pin, uint8_t val) +{ + static uint16_t gpio_pin_offset[USB64_PIN_MAX]; + static uint8_t initialised[USB64_PIN_MAX] = {0}; + uint32_t mode = (val == N64_OUTPUT) ? GPIO_MODE_OUTPUT_PP : GPIO_MODE_INPUT; + + //Get the backend gpio from the pin number + dev_gpio_t *gpio = n64hal_pin_to_gpio(pin); + if (gpio == NULL) + { + return; + } + + //Get the pin offset of the gpio. ie. GPIO6 = 6. This only happens on the first call + //for efficiency + if (initialised[pin] == 0) + { + for (uint8_t i = 0; i < 16; i++) + { + if (gpio->pin & (1UL << i)) + gpio_pin_offset[pin] = i; + } + initialised[pin] = 1; + } + //Change the pin mode from input/outputpp + //When output, the line is driven low, when input is it floating (pulled up by resistor) + uint32_t temp = gpio->port->MODER; + uint32_t offset = gpio_pin_offset[pin]; + temp &= ~(GPIO_MODER_MODER0 << (offset * 2U)); + temp |= ((mode & GPIO_MODER_MODER0) << (offset * 2U)); + gpio->port->MODER = temp; +} + +uint8_t n64hal_input_read(usb64_pin_t pin) +{ + dev_gpio_t *gpio = n64hal_pin_to_gpio(pin); + if (gpio != NULL) + { + return HAL_GPIO_ReadPin(gpio->port, gpio->pin); + } + return 0; +} + +void n64hal_output_set(usb64_pin_t pin, uint8_t level) +{ + dev_gpio_t *gpio = n64hal_pin_to_gpio(pin); + if (gpio != NULL) + { + HAL_GPIO_WritePin(gpio->port, gpio->pin, (GPIO_PinState)level); + } + return; +} + +void n64hal_read_extram(void *rx_buff, void *src, uint32_t offset, uint32_t len) +{ + //External ram is just memory mapped. memcpy is fine + memcpy(rx_buff, (void *)((uintptr_t)src + offset), len); +} + +void n64hal_write_extram(void *tx_buff, void *dst, uint32_t offset, uint32_t len) +{ + //External ram is just memory mapped. memcpy is fine + memcpy((void *)((uintptr_t)dst + offset), tx_buff, len); + memory_mark_dirty(dst); +} + +void *n64hal_malloc(uint32_t len) +{ + return memory_dev_malloc(len); +} + +void n64hal_free(void *addr) +{ + memory_dev_free(addr); +} + +uint32_t n64hal_list_gb_roms(char **gb_list, uint32_t max) +{ + //Retrieve full directory list + char *file_list[256]; + uint32_t num_files = fileio_list_directory(file_list, 256); + + //Find only files with .gb or gbc extensions to populate rom list. + uint32_t rom_count = 0; + for (uint32_t i = 0; i < num_files; i++) + { + if (file_list[i] == NULL) + continue; + + if (strstr(file_list[i], ".GB\0") != NULL || strstr(file_list[i], ".GBC\0") != NULL || + strstr(file_list[i], ".gb\0") != NULL || strstr(file_list[i], ".gbc\0") != NULL) + { + if (rom_count < max) + { + gb_list[rom_count] = (char *)memory_dev_malloc(strlen(file_list[i]) + 1); + strcpy(gb_list[rom_count], file_list[i]); + rom_count++; + } + } + //Free file list as we go + memory_dev_free(file_list[i]); + } + return rom_count; +} + +void n64hal_read_storage(char *name, uint32_t file_offset, uint8_t *data, uint32_t len) +{ + fileio_read_from_file(name, file_offset, data, len); +} + +void Error_Handler(void) +{ + HAL_UART_Transmit(&huart6, (uint8_t *)"Error_Handler\n", 14, 5000); + __disable_irq(); + while (1) + { + } +} + +//STM32 specifics + +//STM32F7 has a powerful, configurable CRC unit. Use it instead of my software one which needs a fast CPU +extern "C" uint8_t n64_get_crc(uint8_t *data) +{ + return HAL_CRC_Calculate(&hcrc, (uint32_t *)data, 32); +} + +extern "C" void EXTI4_IRQHandler(void) +{ + if (n64_4) + { + n64_4(); + } + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4); +} + +extern "C" void EXTI3_IRQHandler(void) +{ + if (n64_3) + { + n64_3(); + } + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3); +} + +extern "C" void EXTI0_IRQHandler(void) +{ + if (n64_2) + { + n64_2(); + } + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); +} + +extern "C" void EXTI1_IRQHandler(void) +{ + if (n64_1) + { + n64_1(); + } + HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1); +} + +void SystemClock_Config(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + + /** Configure LSE Drive Capability + */ + HAL_PWR_EnableBkUpAccess(); + /** Configure the main internal regulator output voltage + */ + __HAL_RCC_PWR_CLK_ENABLE(); + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; + RCC_OscInitStruct.LSIState = RCC_LSI_ON; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + RCC_OscInitStruct.PLL.PLLM = 25; + RCC_OscInitStruct.PLL.PLLN = 400; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; + RCC_OscInitStruct.PLL.PLLQ = 4; + RCC_OscInitStruct.PLL.PLLR = 2; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + Error_Handler(); + } + /** Activate the Over-Drive mode + */ + if (HAL_PWREx_EnableOverDrive() != HAL_OK) + { + Error_Handler(); + } + /** Initializes the CPU, AHB and APB buses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_6) != HAL_OK) + { + Error_Handler(); + } + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPDIFRX | RCC_PERIPHCLK_LTDC | + RCC_PERIPHCLK_RTC | RCC_PERIPHCLK_USART1 | + RCC_PERIPHCLK_USART6 | RCC_PERIPHCLK_UART5 | + RCC_PERIPHCLK_SAI1 | RCC_PERIPHCLK_SAI2 | + RCC_PERIPHCLK_I2C1 | RCC_PERIPHCLK_I2C4 | + RCC_PERIPHCLK_SDMMC2 | RCC_PERIPHCLK_CLK48 | + RCC_PERIPHCLK_CEC; + PeriphClkInitStruct.PLLI2S.PLLI2SN = 192; + PeriphClkInitStruct.PLLI2S.PLLI2SP = RCC_PLLP_DIV2; + PeriphClkInitStruct.PLLI2S.PLLI2SR = 2; + PeriphClkInitStruct.PLLI2S.PLLI2SQ = 2; + PeriphClkInitStruct.PLLSAI.PLLSAIN = 192; + PeriphClkInitStruct.PLLSAI.PLLSAIR = 2; + PeriphClkInitStruct.PLLSAI.PLLSAIQ = 3; + PeriphClkInitStruct.PLLSAI.PLLSAIP = RCC_PLLSAIP_DIV4; + PeriphClkInitStruct.PLLI2SDivQ = 1; + PeriphClkInitStruct.PLLSAIDivQ = 1; + PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_2; + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; + PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI; + PeriphClkInitStruct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLSAI; + PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2; + PeriphClkInitStruct.Uart5ClockSelection = RCC_UART5CLKSOURCE_PCLK1; + PeriphClkInitStruct.Usart6ClockSelection = RCC_USART6CLKSOURCE_PCLK2; + PeriphClkInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_PCLK1; + PeriphClkInitStruct.I2c4ClockSelection = RCC_I2C4CLKSOURCE_PCLK1; + PeriphClkInitStruct.CecClockSelection = RCC_CECCLKSOURCE_HSI; + PeriphClkInitStruct.Clk48ClockSelection = RCC_CLK48SOURCE_PLLSAIP; + PeriphClkInitStruct.Sdmmc2ClockSelection = RCC_SDMMC2CLKSOURCE_CLK48; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) + { + Error_Handler(); + } + HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSI, RCC_MCODIV_1); +} diff --git a/src/port_stm32f7/stm37f769-dk/main.h b/src/port_stm32f7/stm37f769-dk/main.h new file mode 100644 index 00000000..491b07cf --- /dev/null +++ b/src/port_stm32f7/stm37f769-dk/main.h @@ -0,0 +1,377 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.h + * @brief : Header for main.c file. + * This file contains the common defines of the application. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2021 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MAIN_H +#define __MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim); + +/* Exported functions prototypes ---------------------------------------------*/ +void Error_Handler(void); + +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +/* Private defines -----------------------------------------------------------*/ +#define LCD_B0_Pin GPIO_PIN_4 +#define LCD_B0_GPIO_Port GPIOE +#define OTG_HS_OverCurrent_Pin GPIO_PIN_3 +#define OTG_HS_OverCurrent_GPIO_Port GPIOE +#define QSPI_D2_Pin GPIO_PIN_2 +#define QSPI_D2_GPIO_Port GPIOE +#define RMII_TXD1_Pin GPIO_PIN_14 +#define RMII_TXD1_GPIO_Port GPIOG +#define FMC_NBL1_Pin GPIO_PIN_1 +#define FMC_NBL1_GPIO_Port GPIOE +#define FMC_NBL0_Pin GPIO_PIN_0 +#define FMC_NBL0_GPIO_Port GPIOE +#define ARDUINO_SCL_D15_Pin GPIO_PIN_8 +#define ARDUINO_SCL_D15_GPIO_Port GPIOB +#define ARDUINO_D3_Pin GPIO_PIN_4 +#define ARDUINO_D3_GPIO_Port GPIOB +#define SWO_Pin GPIO_PIN_3 +#define SWO_GPIO_Port GPIOB +#define SPDIF_RX0_Pin GPIO_PIN_7 +#define SPDIF_RX0_GPIO_Port GPIOD +#define SDMMC_CK_Pin GPIO_PIN_12 +#define SDMMC_CK_GPIO_Port GPIOC +#define ARDUINO_PWM_D9_Pin GPIO_PIN_15 +#define ARDUINO_PWM_D9_GPIO_Port GPIOA +#define SWCLK_Pin GPIO_PIN_14 +#define SWCLK_GPIO_Port GPIOA +#define SWDIO_Pin GPIO_PIN_13 +#define SWDIO_GPIO_Port GPIOA +#define DCMI_D6_Pin GPIO_PIN_5 +#define DCMI_D6_GPIO_Port GPIOE +#define DCMI_D7_Pin GPIO_PIN_6 +#define DCMI_D7_GPIO_Port GPIOE +#define RMII_TXD0_Pin GPIO_PIN_13 +#define RMII_TXD0_GPIO_Port GPIOG +#define ARDUINO_SDA_D14_Pin GPIO_PIN_9 +#define ARDUINO_SDA_D14_GPIO_Port GPIOB +#define VCP_RX_Pin GPIO_PIN_7 +#define VCP_RX_GPIO_Port GPIOB +#define QSPI_NCS_Pin GPIO_PIN_6 +#define QSPI_NCS_GPIO_Port GPIOB +#define FMC_SDNCAS_Pin GPIO_PIN_15 +#define FMC_SDNCAS_GPIO_Port GPIOG +#define RMII_TX_EN_Pin GPIO_PIN_11 +#define RMII_TX_EN_GPIO_Port GPIOG +#define LCD_B1_Pin GPIO_PIN_13 +#define LCD_B1_GPIO_Port GPIOJ +#define OTG_FS_VBUS_Pin GPIO_PIN_12 +#define OTG_FS_VBUS_GPIO_Port GPIOJ +#define FMC_D2_Pin GPIO_PIN_0 +#define FMC_D2_GPIO_Port GPIOD +#define SDMMC_D3_Pin GPIO_PIN_11 +#define SDMMC_D3_GPIO_Port GPIOC +#define SDMMC_D2_Pin GPIO_PIN_10 +#define SDMMC_D2_GPIO_Port GPIOC +#define OTG_FS_P_Pin GPIO_PIN_12 +#define OTG_FS_P_GPIO_Port GPIOA +#define NC1_Pin GPIO_PIN_8 +#define NC1_GPIO_Port GPIOI +#define SAI2_MCLKA_Pin GPIO_PIN_4 +#define SAI2_MCLKA_GPIO_Port GPIOI +#define LCD_DE_Pin GPIO_PIN_7 +#define LCD_DE_GPIO_Port GPIOK +#define LCD_B7_Pin GPIO_PIN_6 +#define LCD_B7_GPIO_Port GPIOK +#define LCD_B6_Pin GPIO_PIN_5 +#define LCD_B6_GPIO_Port GPIOK +#define LCD_B4_Pin GPIO_PIN_12 +#define LCD_B4_GPIO_Port GPIOG +#define SAI2_SDB_Pin GPIO_PIN_10 +#define SAI2_SDB_GPIO_Port GPIOG +#define LCD_B2_Pin GPIO_PIN_14 +#define LCD_B2_GPIO_Port GPIOJ +#define OTG_FS_PowerSwitchOn_Pin GPIO_PIN_5 +#define OTG_FS_PowerSwitchOn_GPIO_Port GPIOD +#define DCMI_D5_Pin GPIO_PIN_3 +#define DCMI_D5_GPIO_Port GPIOD +#define FMC_D3_Pin GPIO_PIN_1 +#define FMC_D3_GPIO_Port GPIOD +#define ARDUINO_D7_Pin GPIO_PIN_3 +#define ARDUINO_D7_GPIO_Port GPIOI +#define ARDUINO_D7_EXTI_IRQn EXTI3_IRQn +#define ARDUINO_D8_Pin GPIO_PIN_2 +#define ARDUINO_D8_GPIO_Port GPIOI +#define ARDUINO_D8_EXTI_IRQn EXTI2_IRQn +#define OTG_FS_N_Pin GPIO_PIN_11 +#define OTG_FS_N_GPIO_Port GPIOA +#define uSD_Detect_Pin GPIO_PIN_13 +#define uSD_Detect_GPIO_Port GPIOC +#define FMC_A0_Pin GPIO_PIN_0 +#define FMC_A0_GPIO_Port GPIOF +#define SAI2_SCKA_Pin GPIO_PIN_5 +#define SAI2_SCKA_GPIO_Port GPIOI +#define SAI2_FSA_Pin GPIO_PIN_7 +#define SAI2_FSA_GPIO_Port GPIOI +#define LCD_HSYNC_Pin GPIO_PIN_10 +#define LCD_HSYNC_GPIO_Port GPIOI +#define SAI2_SDA_Pin GPIO_PIN_6 +#define SAI2_SDA_GPIO_Port GPIOI +#define LCD_B5_Pin GPIO_PIN_4 +#define LCD_B5_GPIO_Port GPIOK +#define LCD_BL_CTRL_Pin GPIO_PIN_3 +#define LCD_BL_CTRL_GPIO_Port GPIOK +#define DCMI_VSYNC_Pin GPIO_PIN_9 +#define DCMI_VSYNC_GPIO_Port GPIOG +#define LCD_B3_Pin GPIO_PIN_15 +#define LCD_B3_GPIO_Port GPIOJ +#define OTG_FS_OverCurrent_Pin GPIO_PIN_4 +#define OTG_FS_OverCurrent_GPIO_Port GPIOD +#define SDMMC_CMD_Pin GPIO_PIN_2 +#define SDMMC_CMD_GPIO_Port GPIOD +#define TP3_Pin GPIO_PIN_15 +#define TP3_GPIO_Port GPIOH +#define ARDUINO_SCK_D13_Pin GPIO_PIN_1 +#define ARDUINO_SCK_D13_GPIO_Port GPIOI +#define OTG_FS_ID_Pin GPIO_PIN_10 +#define OTG_FS_ID_GPIO_Port GPIOA +#define RCC_OSC32_IN_Pin GPIO_PIN_14 +#define RCC_OSC32_IN_GPIO_Port GPIOC +#define FMC_A1_Pin GPIO_PIN_1 +#define FMC_A1_GPIO_Port GPIOF +#define LCD_DISP_Pin GPIO_PIN_12 +#define LCD_DISP_GPIO_Port GPIOI +#define LCD_VSYNC_Pin GPIO_PIN_9 +#define LCD_VSYNC_GPIO_Port GPIOI +#define DCMI_PWR_EN_Pin GPIO_PIN_13 +#define DCMI_PWR_EN_GPIO_Port GPIOH +#define DCMI_D4_Pin GPIO_PIN_14 +#define DCMI_D4_GPIO_Port GPIOH +#define ARDUINO_PWM_CS_D5_Pin GPIO_PIN_0 +#define ARDUINO_PWM_CS_D5_GPIO_Port GPIOI +#define VCP_TX_Pin GPIO_PIN_9 +#define VCP_TX_GPIO_Port GPIOA +#define RCC_OSC32_OUT_Pin GPIO_PIN_15 +#define RCC_OSC32_OUT_GPIO_Port GPIOC +#define LCD_G6_Pin GPIO_PIN_1 +#define LCD_G6_GPIO_Port GPIOK +#define LCD_G7_Pin GPIO_PIN_2 +#define LCD_G7_GPIO_Port GPIOK +#define ARDUINO_PWM_D10_Pin GPIO_PIN_8 +#define ARDUINO_PWM_D10_GPIO_Port GPIOA +#define OSC_25M_Pin GPIO_PIN_0 +#define OSC_25M_GPIO_Port GPIOH +#define FMC_A2_Pin GPIO_PIN_2 +#define FMC_A2_GPIO_Port GPIOF +#define LCD_INT_Pin GPIO_PIN_13 +#define LCD_INT_GPIO_Port GPIOI +#define LCD_R0_Pin GPIO_PIN_15 +#define LCD_R0_GPIO_Port GPIOI +#define LCD_G4_Pin GPIO_PIN_11 +#define LCD_G4_GPIO_Port GPIOJ +#define LCD_G5_Pin GPIO_PIN_0 +#define LCD_G5_GPIO_Port GPIOK +#define ARDUINO_RX_D0_Pin GPIO_PIN_7 +#define ARDUINO_RX_D0_GPIO_Port GPIOC +#define FMC_A3_Pin GPIO_PIN_3 +#define FMC_A3_GPIO_Port GPIOF +#define LCD_CLK_Pin GPIO_PIN_14 +#define LCD_CLK_GPIO_Port GPIOI +#define LCD_G1_Pin GPIO_PIN_8 +#define LCD_G1_GPIO_Port GPIOJ +#define LCD_G3_Pin GPIO_PIN_10 +#define LCD_G3_GPIO_Port GPIOJ +#define FMC_SDCLK_Pin GPIO_PIN_8 +#define FMC_SDCLK_GPIO_Port GPIOG +#define ARDUINO_TX_D1_Pin GPIO_PIN_6 +#define ARDUINO_TX_D1_GPIO_Port GPIOC +#define FMC_A4_Pin GPIO_PIN_4 +#define FMC_A4_GPIO_Port GPIOF +#define FMC_SDNME_Pin GPIO_PIN_5 +#define FMC_SDNME_GPIO_Port GPIOH +#define FMC_SDNE0_Pin GPIO_PIN_3 +#define FMC_SDNE0_GPIO_Port GPIOH +#define LCD_G0_Pin GPIO_PIN_7 +#define LCD_G0_GPIO_Port GPIOJ +#define LCD_G2_Pin GPIO_PIN_9 +#define LCD_G2_GPIO_Port GPIOJ +#define ARDUINO_D4_Pin GPIO_PIN_7 +#define ARDUINO_D4_GPIO_Port GPIOG +#define ARDUINO_D4_EXTI_IRQn EXTI9_5_IRQn +#define ARDUINO_D2_Pin GPIO_PIN_6 +#define ARDUINO_D2_GPIO_Port GPIOG +#define ARDUINO_D2_EXTI_IRQn EXTI9_5_IRQn +#define ARDUINO_A4_Pin GPIO_PIN_7 +#define ARDUINO_A4_GPIO_Port GPIOF +#define ARDUINO_A5_Pin GPIO_PIN_6 +#define ARDUINO_A5_GPIO_Port GPIOF +#define FMC_A5_Pin GPIO_PIN_5 +#define FMC_A5_GPIO_Port GPIOF +#define NC2_Pin GPIO_PIN_2 +#define NC2_GPIO_Port GPIOH +#define LCD_R7_Pin GPIO_PIN_6 +#define LCD_R7_GPIO_Port GPIOJ +#define FMC_D1_Pin GPIO_PIN_15 +#define FMC_D1_GPIO_Port GPIOD +#define FMC_D15_Pin GPIO_PIN_10 +#define FMC_D15_GPIO_Port GPIOD +#define ARDUINO_A1_Pin GPIO_PIN_10 +#define ARDUINO_A1_GPIO_Port GPIOF +#define ARDUINO_A2_Pin GPIO_PIN_9 +#define ARDUINO_A2_GPIO_Port GPIOF +#define ARDUINO_A3_Pin GPIO_PIN_8 +#define ARDUINO_A3_GPIO_Port GPIOF +#define FMC_SDCKE0_Pin GPIO_PIN_3 +#define FMC_SDCKE0_GPIO_Port GPIOC +#define FMC_D0_Pin GPIO_PIN_14 +#define FMC_D0_GPIO_Port GPIOD +#define FMC_D14_Pin GPIO_PIN_9 +#define FMC_D14_GPIO_Port GPIOD +#define FMC_D13_Pin GPIO_PIN_8 +#define FMC_D13_GPIO_Port GPIOD +#define RMII_MDC_Pin GPIO_PIN_1 +#define RMII_MDC_GPIO_Port GPIOC +#define FMC_A6_Pin GPIO_PIN_12 +#define FMC_A6_GPIO_Port GPIOF +#define FMC_A11_Pin GPIO_PIN_1 +#define FMC_A11_GPIO_Port GPIOG +#define FMC_A9_Pin GPIO_PIN_15 +#define FMC_A9_GPIO_Port GPIOF +#define LCD_R5_Pin GPIO_PIN_4 +#define LCD_R5_GPIO_Port GPIOJ +#define QSPI_D1_Pin GPIO_PIN_12 +#define QSPI_D1_GPIO_Port GPIOD +#define QSPI_D3_Pin GPIO_PIN_13 +#define QSPI_D3_GPIO_Port GPIOD +#define EXT_RST_Pin GPIO_PIN_3 +#define EXT_RST_GPIO_Port GPIOG +#define RMII_RXER_Pin GPIO_PIN_2 +#define RMII_RXER_GPIO_Port GPIOG +#define LCD_R6_Pin GPIO_PIN_5 +#define LCD_R6_GPIO_Port GPIOJ +#define DCMI_D3_Pin GPIO_PIN_12 +#define DCMI_D3_GPIO_Port GPIOH +#define RMII_REF_CLK_Pin GPIO_PIN_1 +#define RMII_REF_CLK_GPIO_Port GPIOA +#define ARDUINO_A0_Pin GPIO_PIN_0 +#define ARDUINO_A0_GPIO_Port GPIOA +#define DCMI_HSYNC_Pin GPIO_PIN_4 +#define DCMI_HSYNC_GPIO_Port GPIOA +#define RMII_RXD0_Pin GPIO_PIN_4 +#define RMII_RXD0_GPIO_Port GPIOC +#define FMC_A7_Pin GPIO_PIN_13 +#define FMC_A7_GPIO_Port GPIOF +#define FMC_A10_Pin GPIO_PIN_0 +#define FMC_A10_GPIO_Port GPIOG +#define LCD_R4_Pin GPIO_PIN_3 +#define LCD_R4_GPIO_Port GPIOJ +#define FMC_D5_Pin GPIO_PIN_8 +#define FMC_D5_GPIO_Port GPIOE +#define QSPI_D0_Pin GPIO_PIN_11 +#define QSPI_D0_GPIO_Port GPIOD +#define FMC_BA1_Pin GPIO_PIN_5 +#define FMC_BA1_GPIO_Port GPIOG +#define FMC_BA0_Pin GPIO_PIN_4 +#define FMC_BA0_GPIO_Port GPIOG +#define LCD_SCL_Pin GPIO_PIN_7 +#define LCD_SCL_GPIO_Port GPIOH +#define DCMI_D0_Pin GPIO_PIN_9 +#define DCMI_D0_GPIO_Port GPIOH +#define DCMI_D2_Pin GPIO_PIN_11 +#define DCMI_D2_GPIO_Port GPIOH +#define RMII_MDIO_Pin GPIO_PIN_2 +#define RMII_MDIO_GPIO_Port GPIOA +#define RMII_RXD1_Pin GPIO_PIN_5 +#define RMII_RXD1_GPIO_Port GPIOC +#define FMC_A8_Pin GPIO_PIN_14 +#define FMC_A8_GPIO_Port GPIOF +#define LCD_R3_Pin GPIO_PIN_2 +#define LCD_R3_GPIO_Port GPIOJ +#define FMC_SDNRAS_Pin GPIO_PIN_11 +#define FMC_SDNRAS_GPIO_Port GPIOF +#define FMC_D6_Pin GPIO_PIN_9 +#define FMC_D6_GPIO_Port GPIOE +#define FMC_D8_Pin GPIO_PIN_11 +#define FMC_D8_GPIO_Port GPIOE +#define FMC_D11_Pin GPIO_PIN_14 +#define FMC_D11_GPIO_Port GPIOE +#define ULPI_D3_Pin GPIO_PIN_10 +#define ULPI_D3_GPIO_Port GPIOB +#define ARDUINO_PWM_D6_Pin GPIO_PIN_6 +#define ARDUINO_PWM_D6_GPIO_Port GPIOH +#define LCD_SDA_Pin GPIO_PIN_8 +#define LCD_SDA_GPIO_Port GPIOH +#define DCMI_D1_Pin GPIO_PIN_10 +#define DCMI_D1_GPIO_Port GPIOH +#define RMII_CRS_DV_Pin GPIO_PIN_7 +#define RMII_CRS_DV_GPIO_Port GPIOA +#define LCD_R1_Pin GPIO_PIN_0 +#define LCD_R1_GPIO_Port GPIOJ +#define LCD_R2_Pin GPIO_PIN_1 +#define LCD_R2_GPIO_Port GPIOJ +#define FMC_D4_Pin GPIO_PIN_7 +#define FMC_D4_GPIO_Port GPIOE +#define FMC_D7_Pin GPIO_PIN_10 +#define FMC_D7_GPIO_Port GPIOE +#define FMC_D9_Pin GPIO_PIN_12 +#define FMC_D9_GPIO_Port GPIOE +#define FMC_D12_Pin GPIO_PIN_15 +#define FMC_D12_GPIO_Port GPIOE +#define FMC_D10_Pin GPIO_PIN_13 +#define FMC_D10_GPIO_Port GPIOE +#define ARDUINO_MISO_D12_Pin GPIO_PIN_14 +#define ARDUINO_MISO_D12_GPIO_Port GPIOB +#define ARDUINO_MOSI_PWM_D11_Pin GPIO_PIN_15 +#define ARDUINO_MOSI_PWM_D11_GPIO_Port GPIOB +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +#ifdef __cplusplus +} +#endif + +#endif /* __MAIN_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/stm37f769-dk/memory_stm32.cpp b/src/port_stm32f7/stm37f769-dk/memory_stm32.cpp new file mode 100644 index 00000000..2d6440dd --- /dev/null +++ b/src/port_stm32f7/stm37f769-dk/memory_stm32.cpp @@ -0,0 +1,71 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include "common.h" +#include "tinyalloc.h" +#include "memory.h" + +static uint32_t extram_start = 0; +static uint32_t extram_end = 0; + +bool memory_dev_init() +{ + extram_start = SDRAM_DEVICE_ADDR + 0x200000; + extram_end = extram_start + SDRAM_DEVICE_SIZE - 0x200000; + + //There's 8MB usable SDRAM on the f750-k board located from 0xC0000000 + //The first 2MB are reversed for the LCD. extram_start starts just after this + //I create a new heap at this location for allocating large files + extern SDRAM_HandleTypeDef sdramHandle; + if (sdramHandle.State != HAL_SDRAM_STATE_READY) + { + BSP_SDRAM_Init(); + } + + uint32_t extram_bytes = extram_end - extram_start; + ta_init((void *)(extram_start), //Base of heap + (void *)(extram_end), //End of heap + extram_bytes / 32768, //Number of memory chunks (32k/per chunk) + 16, //Smaller chunks than this won't split + 4); //32 word size alignment + + debug_print_memory("[MEMORY] External memory initialised\n"); + debug_print_memory("[MEMORY] Detected %ukB\n", extram_bytes / 1024); + debug_print_memory("[MEMORY] Heap start: %08x\n", (void *)(extram_start)); + debug_print_memory("[MEMORY] Heap end: %08x\n", (void *)(extram_end)); + debug_print_memory("[MEMORY] Number of memory chunks: %u\n", extram_bytes / 32768); + return true; +} + +void *memory_dev_malloc(uint32_t len) +{ + void *pt = ta_alloc(len); + if (pt == NULL) + { + debug_print_error("[MEMORY] ERROR, could not allocate memory\n"); + } + return pt; +} + +void memory_dev_free(void *add) +{ + if ((uint32_t)add >= extram_start) + { + ta_free(add); + } + else + { + free(add); + } +} + +/* + * Function: Detect the amount of external RAM installed. This prints it to the LCD and a number > 0 is required for TPAK + * emulation. If you device has loads of internal RAM suitable for TPAK emulation (>2MB or so) which you want to use, set this to a non-zero number. + * ---------------------------- + * Returns: How many MB of external RAM is installed. + */ +uint8_t memory_get_ext_ram_size() +{ + return (extram_end - extram_start) / 1024 / 1024; +} diff --git a/src/port_stm32f7/stm37f769-dk/port_conf.h b/src/port_stm32f7/stm37f769-dk/port_conf.h new file mode 100644 index 00000000..08deb775 --- /dev/null +++ b/src/port_stm32f7/stm37f769-dk/port_conf.h @@ -0,0 +1,71 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT +#ifndef _USB64_CONF_h +#define _USB64_CONF_h + +//Specific headers for this port +#include +#include "stm32f769i_discovery_lcd.h" +#include "stm32f769i_discovery_sd.h" +#include "stm32f769i_discovery_sdram.h" +#include "main.h" + +/* PIN MAPPING - Teensy uses an Arduino Backend, we just assign the enum to the Arduino Pin number + USB64_PIN_MAX must be the largest pin number in the list add one*/ +typedef enum { + USER_LED_PIN = -1, + N64_FRAME_PIN = -1, + HW_RUMBLE = -1, + N64_CONSOLE_SENSE_PIN, + N64_CONTROLLER_1_PIN, + N64_CONTROLLER_2_PIN, + N64_CONTROLLER_3_PIN, + N64_CONTROLLER_4_PIN, +/* + N64_FRAME_PIN, + USER_LED_PIN, + HW_A, + HW_B, + HW_CU, + HW_CD, + HW_CL, + HW_CR, + HW_DU, + HW_DD, + HW_DL, + HW_DR, + HW_START, + HW_Z, + HW_R, + HW_L, + HW_RUMBLE, //Output, 1 when should be rumbling + HW_EN, //Active low, pulled high + HW_X, //Analog input, 0V to VCC. VCC/2 centre + HW_Y, //Analog input, 0V to VCC. VCC/2 centre + TFT_DC, + TFT_CS, + TFT_MOSI, + TFT_SCK, + TFT_MISO, + TFT_RST, +*/ + USB64_PIN_MAX, +} usb64_pin_t; + +/* TFT DISPLAY */ +#define ENABLE_TFT_DISPLAY 1 +#define TFT_WIDTH 800 +#define TFT_HEIGHT 472 +#define TFT_PIXEL_SIZE 4 +#define TFT_USE_FRAMEBUFFER 0 + +/* Define for variables to store in flash only */ +#ifndef PROGMEM +#define PROGMEM __attribute__((section(".text.rodata"))) +#endif +/* Define for function to store in flash only */ +#ifndef FLASHMEM +#define FLASHMEM __attribute__ ((section (".text.code"))) +#endif + +#endif diff --git a/src/port_stm32f7/stm37f769-dk/tft_stm32.cpp b/src/port_stm32f7/stm37f769-dk/tft_stm32.cpp new file mode 100644 index 00000000..9feca6e3 --- /dev/null +++ b/src/port_stm32f7/stm37f769-dk/tft_stm32.cpp @@ -0,0 +1,88 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include "common.h" +#include "tft.h" +#include "controller_icon.h" +#include "usb64_logo.h" +#include "GuiLite.h" + +#define TFT_FRAMEBUFFER_SIZE (TFT_WIDTH * TFT_HEIGHT * TFT_PIXEL_SIZE) +c_surface *psurface_guilite = NULL; +c_display *pdisplay_guilite = NULL; +#if TFT_USE_FRAMEBUFFER +static uint8_t *_framebuffer = (uint8_t *)(LCD_FB_START_ADDRESS); +#else +static uint8_t *_framebuffer = (uint8_t *)(LCD_FB_START_ADDRESS); +struct EXTERNAL_GFX_OP my_gfx_op; +#endif + +static void _tft_assert(const char *file, int line) +{ + debug_print_error("[TFT] Error: Assert in %s on line %d\n", file, line); + while (1) + ; +} + +static void _tft_log_out(const char *log) +{ + debug_print_status(log); +} + +#if TFT_USE_FRAMEBUFFER == 0 +static void _draw_pixel(int x, int y, unsigned int rgb) +{ + //Device specific pixel draw + BSP_LCD_DrawPixel(x, y, rgb); +} + +static void _fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) +{ + BSP_LCD_SetTextColor(rgb); + BSP_LCD_FillRect(x0, y0, x1 - x0, y1 - y0); + //Weird, but the above FillRect leaves before finshing properly. This fixes it? + BSP_LCD_FillRect(x0, y0, 1, 1); +} +#endif + +void tft_dev_draw(bool force) +{ + //Dont need to do anything. This TFT just updates from the SDRAM buffer automatically. +} + +extern "C" void BSP_LCD_ClockConfig(LTDC_HandleTypeDef *hltdc, void *Params) +{ + //Overrise the internal clock config as it messes with other clock divs and multipliers. + //Dont do anything. All clocks are setup properly at boot +} + +void tft_dev_init() +{ +#if TFT_USE_FRAMEBUFFER + static c_surface surface(TFT_WIDTH, TFT_HEIGHT, 2, Z_ORDER_LEVEL_0); + static c_display display(_framebuffer, TFT_WIDTH, TFT_HEIGHT, &surface); + psurface_guilite = &surface; + pdisplay_guilite = &display; +#else + static c_surface_no_fb surface(TFT_WIDTH, TFT_HEIGHT, 2, &my_gfx_op, Z_ORDER_LEVEL_0); + static c_display display(NULL, TFT_WIDTH, TFT_HEIGHT, &surface); + my_gfx_op.draw_pixel = _draw_pixel; + my_gfx_op.fill_rect = _fill_rect; +#endif + psurface_guilite = &surface; + pdisplay_guilite = &display; + register_debug_function(_tft_assert, _tft_log_out); +#if (ENABLE_TFT_DISPLAY >= 1) + BSP_LCD_Init(); + BSP_LCD_LayerDefaultInit(0, (uint32_t)_framebuffer); + BSP_LCD_SelectLayer(0); + BSP_LCD_SetBackColor(TFT_BG_COLOR); + BSP_LCD_Clear(TFT_BG_COLOR); + BSP_LCD_DisplayOn(); +#endif +} + +bool tft_dev_is_busy() +{ + return 0; +} diff --git a/src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp b/src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp new file mode 100644 index 00000000..89b47fe0 --- /dev/null +++ b/src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp @@ -0,0 +1,44 @@ +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include "common.h" +#include "stm32f7xx_hal.h" +#include "tusb.h" + +HCD_HandleTypeDef hhcd_USB_OTG_FS; + +//Forward the OTG_FS interrupt to the tinyusb handler +extern "C" void hcd_int_handler(uint8_t rhport); +extern "C" void OTG_FS_IRQHandler(void) +{ + hcd_int_handler(0); +} + +void usbh_dev_init() +{ + //Enable clocks + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + GPIO_InitTypeDef GPIO_InitStruct; + + //Turn on 5V output + GPIO_InitStruct.Pin = OTG_FS_PowerSwitchOn_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(OTG_FS_PowerSwitchOn_GPIO_Port, &GPIO_InitStruct); + HAL_GPIO_WritePin(OTG_FS_PowerSwitchOn_GPIO_Port, OTG_FS_PowerSwitchOn_Pin, GPIO_PIN_RESET); + + //Setup USB data pins + GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); + HAL_NVIC_SetPriority(OTG_FS_IRQn, 6, 0); + HAL_NVIC_EnableIRQ(OTG_FS_IRQn); +} From daf90c2f977a2b53d56efeede82f571a929d923f Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 15 Jan 2022 16:41:14 +1030 Subject: [PATCH 099/121] STM32F768i: Boots now --- platformio.ini | 5 +++-- src/port_stm32f7/stm37f769-dk/hal_stm32.cpp | 6 +++--- src/port_stm32f7/stm37f769-dk/port_conf.h | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/platformio.ini b/platformio.ini index c1a23aed..d2e7efc3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -128,7 +128,7 @@ build_flags = platform = ststm32 board = disco_f769ni framework = stm32cube -board_build.ldscript = src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld +; board_build.ldscript = src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld src_filter = ${common_env_data.src_filter} @@ -136,7 +136,8 @@ src_filter = + + + - + + + + + + build_flags = diff --git a/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp b/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp index 763b9c8c..cac9c061 100644 --- a/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp +++ b/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp @@ -46,9 +46,9 @@ void n64hal_system_init() __disable_irq(); //Move the interrupt vector table from Flash to RAM. Should have better interrupt perf and consistency - void *vtor = (void *)RAMDTCM_BASE; - memcpy(vtor, (void *)SCB->VTOR, 0x200); - SCB->VTOR = (uint32_t)vtor; + //void *vtor = (void *)RAMDTCM_BASE; + //memcpy(vtor, (void *)SCB->VTOR, 0x200); + //SCB->VTOR = (uint32_t)vtor; __enable_irq(); __HAL_RCC_CRC_CLK_ENABLE(); diff --git a/src/port_stm32f7/stm37f769-dk/port_conf.h b/src/port_stm32f7/stm37f769-dk/port_conf.h index 08deb775..d73d3db6 100644 --- a/src/port_stm32f7/stm37f769-dk/port_conf.h +++ b/src/port_stm32f7/stm37f769-dk/port_conf.h @@ -61,11 +61,11 @@ typedef enum { /* Define for variables to store in flash only */ #ifndef PROGMEM -#define PROGMEM __attribute__((section(".text.rodata"))) +#define PROGMEM #endif /* Define for function to store in flash only */ #ifndef FLASHMEM -#define FLASHMEM __attribute__ ((section (".text.code"))) +#define FLASHMEM #endif #endif From b7e18a30bbbd80388539b693fe6c1adf6b74998e Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 15 Jan 2022 17:23:20 +1030 Subject: [PATCH 100/121] STM32F768i: Support USB HS port --- platformio.ini | 3 + src/lib/tusb_config.h | 6 ++ src/port_stm32f7/common/stm32fxx_hcd.c | 9 +-- src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp | 80 +++++++++++++++----- 4 files changed, 76 insertions(+), 22 deletions(-) diff --git a/platformio.ini b/platformio.ini index d2e7efc3..48235291 100644 --- a/platformio.ini +++ b/platformio.ini @@ -123,6 +123,7 @@ build_flags = -DAPPLICATION_ADDRESS=0x90000000U ;My entry point is in QSPI Flash for this board -DUSE_HAL_DRIVER -DSTM32F750xx + -DUSB_USB_FS [env:disco_f769ni] platform = ststm32 @@ -149,6 +150,8 @@ build_flags = -DCFG_TUSB_MCU=OPT_MCU_STM32F7 -DAPPLICATION_ADDRESS=0x8000000U ;Entry point is internal FLASH. -DUSE_HAL_DRIVER + -DSTM32F769xx + -DUSB_USB_HS [env:template] platform = native diff --git a/src/lib/tusb_config.h b/src/lib/tusb_config.h index 89ec9654..1f71dd09 100644 --- a/src/lib/tusb_config.h +++ b/src/lib/tusb_config.h @@ -41,6 +41,12 @@ #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST | OPT_MODE_FULL_SPEED) +#elif CFG_TUSB_MCU == OPT_MCU_STM32F7 +#ifdef USB_USB_HS + #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED) +#else + #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | OPT_MODE_FULL_SPEED) +#endif #else #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST | OPT_MODE_FULL_SPEED) #endif diff --git a/src/port_stm32f7/common/stm32fxx_hcd.c b/src/port_stm32f7/common/stm32fxx_hcd.c index cdd01981..33dd3920 100644 --- a/src/port_stm32f7/common/stm32fxx_hcd.c +++ b/src/port_stm32f7/common/stm32fxx_hcd.c @@ -374,15 +374,14 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport) // Initialize controller to host mode bool hcd_init(uint8_t rhport) { - (void)rhport; HAL_StatusTypeDef res = HAL_ERROR; - hhcd.Instance = USB_OTG_FS; + hhcd.Instance = (rhport == 0) ? USB_OTG_FS : USB_OTG_HS; hhcd.Init.Host_channels = MAX_PIPES; hhcd.Init.dma_enable = 0; hhcd.Init.low_power_enable = 0; - hhcd.Init.phy_itface = HCD_PHY_EMBEDDED; + hhcd.Init.phy_itface = (rhport == 0) ? HCD_PHY_EMBEDDED : USB_OTG_ULPI_PHY; hhcd.Init.Sof_enable = 1; - hhcd.Init.speed = HCD_SPEED_FULL; + hhcd.Init.speed = (rhport == 0) ? HCD_SPEED_FULL : HCD_SPEED_HIGH; hhcd.Init.vbus_sensing_enable = 0; hhcd.Init.lpm_enable = 0; res = HAL_HCD_Init(&hhcd); @@ -390,7 +389,7 @@ bool hcd_init(uint8_t rhport) { res = HAL_HCD_Start(&hhcd); } - HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + HAL_NVIC_EnableIRQ((rhport == 0) ? OTG_FS_IRQn : OTG_HS_IRQn); return (res == HAL_OK); } diff --git a/src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp b/src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp index 89b47fe0..52e3fb62 100644 --- a/src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp +++ b/src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp @@ -9,36 +9,82 @@ HCD_HandleTypeDef hhcd_USB_OTG_FS; //Forward the OTG_FS interrupt to the tinyusb handler extern "C" void hcd_int_handler(uint8_t rhport); -extern "C" void OTG_FS_IRQHandler(void) + +extern "C" void OTG_HS_IRQHandler(void) { - hcd_int_handler(0); + hcd_int_handler(1); } +#define ULPI_STP_Pin GPIO_PIN_0 +#define ULPI_STP_GPIO_Port GPIOC +#define ULPI_D7_Pin GPIO_PIN_5 +#define ULPI_D7_GPIO_Port GPIOB +#define ULPI_D2_Pin GPIO_PIN_1 +#define ULPI_D2_GPIO_Port GPIOB +#define ULPI_D1_Pin GPIO_PIN_0 +#define ULPI_D1_GPIO_Port GPIOB +#define ULPI_D4_Pin GPIO_PIN_11 +#define ULPI_D4_GPIO_Port GPIOB +#define ULPI_D6_Pin GPIO_PIN_13 +#define ULPI_D6_GPIO_Port GPIOB +#define ULPI_D5_Pin GPIO_PIN_12 +#define ULPI_D5_GPIO_Port GPIOB +#define ULPI_DIR_Pin GPIO_PIN_11 +#define ULPI_DIR_GPIO_Port GPIOI +#define ULPI_NXT_Pin GPIO_PIN_4 +#define ULPI_NXT_GPIO_Port GPIOH +#define ULPI_CLK_Pin GPIO_PIN_5 +#define ULPI_CLK_GPIO_Port GPIOA +#define ULPI_D0_Pin GPIO_PIN_3 +#define ULPI_D0_GPIO_Port GPIOA void usbh_dev_init() { - //Enable clocks + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOD_CLK_ENABLE(); - GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitStruct.Pin = ULPI_D7_Pin | ULPI_D6_Pin | ULPI_D5_Pin | ULPI_D3_Pin | ULPI_D2_Pin | ULPI_D1_Pin | ULPI_D4_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = ULPI_DIR_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(ULPI_DIR_GPIO_Port, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = ULPI_NXT_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(ULPI_NXT_GPIO_Port, &GPIO_InitStruct); - //Turn on 5V output - GPIO_InitStruct.Pin = OTG_FS_PowerSwitchOn_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pin = ULPI_STP_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - HAL_GPIO_Init(OTG_FS_PowerSwitchOn_GPIO_Port, &GPIO_InitStruct); - HAL_GPIO_WritePin(OTG_FS_PowerSwitchOn_GPIO_Port, OTG_FS_PowerSwitchOn_Pin, GPIO_PIN_RESET); + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; + HAL_GPIO_Init(ULPI_STP_GPIO_Port, &GPIO_InitStruct); - //Setup USB data pins - GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12; + GPIO_InitStruct.Pin = ULPI_CLK_Pin | ULPI_D0_Pin; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; + GPIO_InitStruct.Alternate = GPIO_AF10_OTG_HS; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); - HAL_NVIC_SetPriority(OTG_FS_IRQn, 6, 0); - HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); + __HAL_RCC_USB_OTG_HS_ULPI_CLK_ENABLE(); + + HAL_NVIC_SetPriority(OTG_HS_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(OTG_HS_IRQn); } From f284583d25ba3df6c1188edaeced6a13b322f6dd Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 15 Jan 2022 18:02:42 +1030 Subject: [PATCH 101/121] stm32f7 usbh: Force full speed mode, properly handle transfer speeds --- src/port_stm32f7/common/stm32fxx_hcd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/port_stm32f7/common/stm32fxx_hcd.c b/src/port_stm32f7/common/stm32fxx_hcd.c index 33dd3920..ac1c9c48 100644 --- a/src/port_stm32f7/common/stm32fxx_hcd.c +++ b/src/port_stm32f7/common/stm32fxx_hcd.c @@ -150,16 +150,18 @@ static usbh_endpoint_t *_find_endpoint(uint8_t dev_addr, uint8_t ep_addr) static bool _endpoint_xfer(usbh_endpoint_t *ep, uint8_t is_setup) { + static const uint8_t speed[3] = {HCD_DEVICE_SPEED_FULL, HCD_DEVICE_SPEED_LOW, HCD_DEVICE_SPEED_HIGH}; HAL_StatusTypeDef ret = HAL_OK; HCD_HCTypeDef *hc = &hhcd.hc[ep->ch_num]; uint8_t hc_ep_addr = hc->ep_num | ((hc->ep_is_in) ? 0x80 : 0x00); + tusb_speed_t tusb_speed = tuh_speed_get(ep->dev_addr); if (hc->dev_addr != ep->dev_addr || hc_ep_addr != ep->ep_desc.bEndpointAddress || hc->dev_addr == 0) { ret = HAL_HCD_HC_Init(&hhcd, ep->ch_num, ep->ep_desc.bEndpointAddress, ep->dev_addr, - HAL_HCD_GetCurrentSpeed(&hhcd), //FIXME tuh_speed_get? + speed[tusb_speed], ep->ep_type, ep->ep_desc.wMaxPacketSize); } @@ -381,7 +383,7 @@ bool hcd_init(uint8_t rhport) hhcd.Init.low_power_enable = 0; hhcd.Init.phy_itface = (rhport == 0) ? HCD_PHY_EMBEDDED : USB_OTG_ULPI_PHY; hhcd.Init.Sof_enable = 1; - hhcd.Init.speed = (rhport == 0) ? HCD_SPEED_FULL : HCD_SPEED_HIGH; + hhcd.Init.speed = HCD_SPEED_FULL; hhcd.Init.vbus_sensing_enable = 0; hhcd.Init.lpm_enable = 0; res = HAL_HCD_Init(&hhcd); From d4a3d3a17fb5c33cb3243ab22a46d484fc333617 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 15 Jan 2022 18:04:08 +1030 Subject: [PATCH 102/121] TinyUSB: Update submodule --- src/lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/tinyusb b/src/lib/tinyusb index b4d1216a..4343d1a3 160000 --- a/src/lib/tinyusb +++ b/src/lib/tinyusb @@ -1 +1 @@ -Subproject commit b4d1216ae46e95753047850ad8e30fbbd8851a12 +Subproject commit 4343d1a3961e3f92e2aa65f84b59616b51a4eb04 From 9c56fe5091aa600cd51d7ffc8a2c677fcc8b5aa3 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 15 Jan 2022 19:44:46 +1030 Subject: [PATCH 103/121] STM32F769I: Re-add custom linker --- platformio.ini | 2 +- .../stm37f769-dk/STM32F769NIHX_FLASH.ld | 92 ++++++++----------- src/port_stm32f7/stm37f769-dk/port_conf.h | 4 +- 3 files changed, 39 insertions(+), 59 deletions(-) diff --git a/platformio.ini b/platformio.ini index 48235291..d1b958db 100644 --- a/platformio.ini +++ b/platformio.ini @@ -129,7 +129,7 @@ build_flags = platform = ststm32 board = disco_f769ni framework = stm32cube -; board_build.ldscript = src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld +board_build.ldscript = src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld src_filter = ${common_env_data.src_filter} diff --git a/src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld b/src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld index b6ecbfee..67846ac4 100644 --- a/src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld +++ b/src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld @@ -1,74 +1,70 @@ /* -****************************************************************************** +***************************************************************************** ** -** @file : LinkerScript.ld -** -** @author : Auto-generated by STM32CubeIDE + +** File : LinkerScript.ld ** -** Abstract : Linker script for STM32F769I-DISCO Board embedding STM32F769NIHx Device from stm32f7 series -** 2048Kbytes FLASH -** 512Kbytes RAM +** Abstract : Linker script for STM32F750N8Hx Device with +** 16384KByte FLASH, 320KByte RAM ** ** Set heap size, stack size and stack location according ** to application requirements. ** -** Set memory bank area and size if external memory is used +** Set memory bank area and size if external memory is used. ** ** Target : STMicroelectronics STM32 ** +** ** Distribution: The file is distributed as is, without any warranty ** of any kind. ** -****************************************************************************** -** @attention +** (c)Copyright Ac6. +** You may use this file as-is or modify it according to the needs of your +** project. Distribution of this file (unmodified or modified) is not +** permitted. Ac6 permit registered System Workbench for MCU users the +** rights to distribute the assembled, compiled & linked contents of this +** file as part of an application binary file, provided that it is built +** using the System Workbench for MCU toolchain. ** -**

© Copyright (c) 2022 STMicroelectronics. -** All rights reserved.

-** -** This software component is licensed by ST under BSD 3-Clause license, -** the "License"; You may not use this file except in compliance with the -** License. You may obtain a copy of the License at: -** opensource.org/licenses/BSD-3-Clause -** -****************************************************************************** +***************************************************************************** */ /* Entry Point */ ENTRY(Reset_Handler) /* Highest address of the user mode stack */ -_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ - -_Min_Heap_Size = 0x200; /* required amount of heap */ -_Min_Stack_Size = 0x400; /* required amount of stack */ +_estack = 0x20050000; /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x400; /* required amount of heap */ +_Min_Stack_Size = 0x800; /* required amount of stack */ -/* Memories definition */ +/* Specify the memory areas */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K } -/* Sections */ +/* Define output sections */ SECTIONS { - /* The startup code into "FLASH" Rom type memory */ + /* The startup code goes first into FLASH */ .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); - } >FLASH + } >RAM AT> FLASH - /* The program code and other data into "FLASH" Rom type memory */ + /* The program code and other data goes into FLASH */ .text : { . = ALIGN(4); *(.text.Reset_Handler) /* Reset handler needs to be in flash so its available to copy the other code to RAM */ *(.text.code) /* Code that can remain in flash (not speed critical. init code etc) */ *(.text.rodata) /* Read only data that can remain in flash to save RAM */ - *(.glue_7) /* glue arm to thumb code */ - *(.glue_7t) /* glue thumb to arm code */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ *(.eh_frame) KEEP (*(.init)) @@ -78,7 +74,7 @@ SECTIONS _etext = .; /* define a global symbols at end of code */ } >FLASH - /* Constant data into "FLASH" Rom type memory */ + /* Constant data goes into FLASH */ .rodata : { . = ALIGN(4); @@ -87,54 +83,39 @@ SECTIONS . = ALIGN(4); } >FLASH - .ARM.extab : { - . = ALIGN(4); - *(.ARM.extab* .gnu.linkonce.armextab.*) - . = ALIGN(4); - } >RAM - + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM .ARM : { - . = ALIGN(4); __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; - . = ALIGN(4); } >RAM .preinit_array : { - . = ALIGN(4); PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array*)) PROVIDE_HIDDEN (__preinit_array_end = .); - . = ALIGN(4); } >FLASH - .init_array : { - . = ALIGN(4); PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array*)) PROVIDE_HIDDEN (__init_array_end = .); - . = ALIGN(4); } >FLASH - .fini_array : { - . = ALIGN(4); PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(SORT(.fini_array.*))) KEEP (*(.fini_array*)) PROVIDE_HIDDEN (__fini_array_end = .); - . = ALIGN(4); } >FLASH - /* Used by the startup to initialize data */ + /* used by the startup to initialize data */ _sidata = LOADADDR(.data); - /* Initialized data sections into "RAM" Ram type memory */ - .data : + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : { . = ALIGN(4); _sdata = .; /* create a global symbol at data start */ @@ -142,17 +123,16 @@ SECTIONS *(.text*) /* .text* sections (code) */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ - + . = ALIGN(4); _edata = .; /* define a global symbol at data end */ - } >RAM AT> FLASH - /* Uninitialized data section into "RAM" Ram type memory */ + /* Uninitialized data section */ . = ALIGN(4); .bss : { - /* This is used by the startup in order to initialize the .bss section */ + /* This is used by the startup in order to initialize the .bss secion */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) @@ -164,7 +144,7 @@ SECTIONS __bss_end__ = _ebss; } >RAM - /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */ + /* User_heap_stack section, used to check that there is enough RAM left */ ._user_heap_stack : { . = ALIGN(8); @@ -175,7 +155,7 @@ SECTIONS . = ALIGN(8); } >RAM - /* Remove information from the compiler libraries */ + /* Remove information from the standard libraries */ /DISCARD/ : { libc.a ( * ) diff --git a/src/port_stm32f7/stm37f769-dk/port_conf.h b/src/port_stm32f7/stm37f769-dk/port_conf.h index d73d3db6..08deb775 100644 --- a/src/port_stm32f7/stm37f769-dk/port_conf.h +++ b/src/port_stm32f7/stm37f769-dk/port_conf.h @@ -61,11 +61,11 @@ typedef enum { /* Define for variables to store in flash only */ #ifndef PROGMEM -#define PROGMEM +#define PROGMEM __attribute__((section(".text.rodata"))) #endif /* Define for function to store in flash only */ #ifndef FLASHMEM -#define FLASHMEM +#define FLASHMEM __attribute__ ((section (".text.code"))) #endif #endif From 1c605a089de2cb207824e1bd08a98c45cfdf7d8a Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 15 Jan 2022 19:45:24 +1030 Subject: [PATCH 104/121] STM32F769I: Fix GPIO interrupts --- src/port_stm32f7/stm37f769-dk/hal_stm32.cpp | 25 +++++++++++---------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp b/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp index cac9c061..6ed65f87 100644 --- a/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp +++ b/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp @@ -46,9 +46,9 @@ void n64hal_system_init() __disable_irq(); //Move the interrupt vector table from Flash to RAM. Should have better interrupt perf and consistency - //void *vtor = (void *)RAMDTCM_BASE; - //memcpy(vtor, (void *)SCB->VTOR, 0x200); - //SCB->VTOR = (uint32_t)vtor; + void *vtor = (void *)RAMDTCM_BASE; + memcpy(vtor, (void *)SCB->VTOR, 0x200); + SCB->VTOR = (uint32_t)vtor; __enable_irq(); __HAL_RCC_CRC_CLK_ENABLE(); @@ -94,9 +94,8 @@ void n64hal_gpio_init() dev_gpio_t *pin; GPIO_InitTypeDef GPIO_InitStruct; - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOI_CLK_ENABLE(); - __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOJ_CLK_ENABLE(); for (int i = 0; i < USB64_PIN_MAX; i++) { @@ -150,8 +149,8 @@ void n64hal_gpio_init() pin = n64hal_pin_to_gpio(N64_CONTROLLER_3_PIN); HAL_GPIO_WritePin(pin->port, pin->pin, GPIO_PIN_RESET); GPIO_InitStruct.Pin = pin->pin; - GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; - GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; HAL_GPIO_Init(pin->port, &GPIO_InitStruct); @@ -186,18 +185,20 @@ void n64hal_debug_write(char c) void n64hal_disable_interrupts() { //Disable the controller input interrupts - HAL_NVIC_DisableIRQ(EXTI9_5_IRQn); - HAL_NVIC_DisableIRQ(EXTI2_IRQn); + HAL_NVIC_DisableIRQ(EXTI0_IRQn); + HAL_NVIC_DisableIRQ(EXTI1_IRQn); HAL_NVIC_DisableIRQ(EXTI3_IRQn); + HAL_NVIC_DisableIRQ(EXTI4_IRQn); HAL_NVIC_DisableIRQ(OTG_FS_IRQn); } void n64hal_enable_interrupts() { //Disable the controller input interrupts - HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); - HAL_NVIC_EnableIRQ(EXTI2_IRQn); + HAL_NVIC_EnableIRQ(EXTI0_IRQn); + HAL_NVIC_EnableIRQ(EXTI1_IRQn); HAL_NVIC_EnableIRQ(EXTI3_IRQn); + HAL_NVIC_EnableIRQ(EXTI4_IRQn); HAL_NVIC_EnableIRQ(OTG_FS_IRQn); } From 82f3d01a073f4184649f5d6e3d9565df76ab57a1 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 15 Jan 2022 20:25:44 +1030 Subject: [PATCH 105/121] STM32F769I: Disable USB HS interrupt for critical code --- src/port_stm32f7/stm37f769-dk/hal_stm32.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp b/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp index 6ed65f87..30ba8337 100644 --- a/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp +++ b/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp @@ -189,7 +189,7 @@ void n64hal_disable_interrupts() HAL_NVIC_DisableIRQ(EXTI1_IRQn); HAL_NVIC_DisableIRQ(EXTI3_IRQn); HAL_NVIC_DisableIRQ(EXTI4_IRQn); - HAL_NVIC_DisableIRQ(OTG_FS_IRQn); + HAL_NVIC_DisableIRQ(OTG_HS_IRQn); } void n64hal_enable_interrupts() @@ -199,7 +199,7 @@ void n64hal_enable_interrupts() HAL_NVIC_EnableIRQ(EXTI1_IRQn); HAL_NVIC_EnableIRQ(EXTI3_IRQn); HAL_NVIC_EnableIRQ(EXTI4_IRQn); - HAL_NVIC_EnableIRQ(OTG_FS_IRQn); + HAL_NVIC_EnableIRQ(OTG_HS_IRQn); } void n64hal_attach_interrupt(usb64_pin_t pin, void (*handler)(void), int mode) From cb39d0635c6547df2feb7565ab1ce4ed2d1c83d3 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sat, 15 Jan 2022 20:37:26 +1030 Subject: [PATCH 106/121] STM32F769I: Clear pending interrupts before leaving --- src/port_stm32f7/stm37f769-dk/hal_stm32.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp b/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp index 30ba8337..37243c86 100644 --- a/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp +++ b/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp @@ -412,6 +412,7 @@ extern "C" void EXTI4_IRQHandler(void) n64_4(); } HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4); + HAL_NVIC_ClearPendingIRQ(EXTI4_IRQn); } extern "C" void EXTI3_IRQHandler(void) @@ -421,6 +422,7 @@ extern "C" void EXTI3_IRQHandler(void) n64_3(); } HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3); + HAL_NVIC_ClearPendingIRQ(EXTI3_IRQn); } extern "C" void EXTI0_IRQHandler(void) @@ -430,6 +432,7 @@ extern "C" void EXTI0_IRQHandler(void) n64_2(); } HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); + HAL_NVIC_ClearPendingIRQ(EXTI0_IRQn); } extern "C" void EXTI1_IRQHandler(void) @@ -439,6 +442,7 @@ extern "C" void EXTI1_IRQHandler(void) n64_1(); } HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1); + HAL_NVIC_ClearPendingIRQ(EXTI1_IRQn); } void SystemClock_Config(void) From 41413879496e336a10d15bd0ef76ecf69dd8e936 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sun, 16 Jan 2022 11:36:56 +1030 Subject: [PATCH 107/121] STM32F769I: Use uart1 VCP for debugging over USB --- src/port_stm32f7/stm37f769-dk/hal_stm32.cpp | 40 ++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp b/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp index 37243c86..b92f4b6b 100644 --- a/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp +++ b/src/port_stm32f7/stm37f769-dk/hal_stm32.cpp @@ -7,7 +7,7 @@ #include "fileio.h" #include "memory.h" -UART_HandleTypeDef huart6; +UART_HandleTypeDef huart; CRC_HandleTypeDef hcrc; static void SystemClock_Config(void); @@ -67,26 +67,26 @@ void n64hal_system_init() void n64hal_debug_init() { GPIO_InitTypeDef GPIO_InitStruct = {0}; - __HAL_RCC_USART6_CLK_ENABLE(); - __HAL_RCC_GPIOC_CLK_ENABLE(); - GPIO_InitStruct.Pin = GPIO_PIN_7 | GPIO_PIN_6; + __HAL_RCC_USART1_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF8_USART6; - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - - huart6.Instance = USART6; - huart6.Init.BaudRate = 115200; - huart6.Init.WordLength = UART_WORDLENGTH_8B; - huart6.Init.StopBits = UART_STOPBITS_1; - huart6.Init.Parity = UART_PARITY_NONE; - huart6.Init.Mode = UART_MODE_TX_RX; - huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE; - huart6.Init.OverSampling = UART_OVERSAMPLING_16; - huart6.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; - huart6.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; - HAL_UART_Init(&huart6); + GPIO_InitStruct.Alternate = GPIO_AF7_USART1; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + huart.Instance = USART1; + huart.Init.BaudRate = 115200; + huart.Init.WordLength = UART_WORDLENGTH_8B; + huart.Init.StopBits = UART_STOPBITS_1; + huart.Init.Parity = UART_PARITY_NONE; + huart.Init.Mode = UART_MODE_TX_RX; + huart.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart.Init.OverSampling = UART_OVERSAMPLING_16; + huart.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; + huart.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; + HAL_UART_Init(&huart); } void n64hal_gpio_init() @@ -179,7 +179,7 @@ void n64hal_gpio_init() void n64hal_debug_write(char c) { - HAL_UART_Transmit(&huart6, (uint8_t *)&c, 1, 5000); + HAL_UART_Transmit(&huart, (uint8_t *)&c, 1, 5000); } void n64hal_disable_interrupts() @@ -390,7 +390,7 @@ void n64hal_read_storage(char *name, uint32_t file_offset, uint8_t *data, uint32 void Error_Handler(void) { - HAL_UART_Transmit(&huart6, (uint8_t *)"Error_Handler\n", 14, 5000); + HAL_UART_Transmit(&huart, (uint8_t *)"Error_Handler\n", 14, 5000); __disable_irq(); while (1) { From 8a0454cd0b4173ca82f79e844c4446a41d8f94d9 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Sun, 16 Jan 2022 11:48:18 +1030 Subject: [PATCH 108/121] STM32: Remove main.h header --- src/port_stm32f7/common/stm32f7xx_it.c | 2 - src/port_stm32f7/stm37f750-dk/main.h | 377 ------------------- src/port_stm32f7/stm37f750-dk/port_conf.h | 1 - src/port_stm32f7/stm37f750-dk/usbh_stm32.cpp | 6 +- src/port_stm32f7/stm37f769-dk/main.h | 377 ------------------- src/port_stm32f7/stm37f769-dk/port_conf.h | 1 - src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp | 2 + 7 files changed, 5 insertions(+), 761 deletions(-) delete mode 100644 src/port_stm32f7/stm37f750-dk/main.h delete mode 100644 src/port_stm32f7/stm37f769-dk/main.h diff --git a/src/port_stm32f7/common/stm32f7xx_it.c b/src/port_stm32f7/common/stm32f7xx_it.c index 888a1e99..5870a088 100644 --- a/src/port_stm32f7/common/stm32f7xx_it.c +++ b/src/port_stm32f7/common/stm32f7xx_it.c @@ -1,5 +1,3 @@ -#include "main.h" - /******************************************************************************/ /* Cortex-M7 Processor Interruption and Exception Handlers */ /******************************************************************************/ diff --git a/src/port_stm32f7/stm37f750-dk/main.h b/src/port_stm32f7/stm37f750-dk/main.h deleted file mode 100644 index 491b07cf..00000000 --- a/src/port_stm32f7/stm37f750-dk/main.h +++ /dev/null @@ -1,377 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file : main.h - * @brief : Header for main.c file. - * This file contains the common defines of the application. - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2021 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __MAIN_H -#define __MAIN_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f7xx_hal.h" - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -/* Exported types ------------------------------------------------------------*/ -/* USER CODE BEGIN ET */ - -/* USER CODE END ET */ - -/* Exported constants --------------------------------------------------------*/ -/* USER CODE BEGIN EC */ - -/* USER CODE END EC */ - -/* Exported macro ------------------------------------------------------------*/ -/* USER CODE BEGIN EM */ - -/* USER CODE END EM */ - -void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim); - -/* Exported functions prototypes ---------------------------------------------*/ -void Error_Handler(void); - -/* USER CODE BEGIN EFP */ - -/* USER CODE END EFP */ - -/* Private defines -----------------------------------------------------------*/ -#define LCD_B0_Pin GPIO_PIN_4 -#define LCD_B0_GPIO_Port GPIOE -#define OTG_HS_OverCurrent_Pin GPIO_PIN_3 -#define OTG_HS_OverCurrent_GPIO_Port GPIOE -#define QSPI_D2_Pin GPIO_PIN_2 -#define QSPI_D2_GPIO_Port GPIOE -#define RMII_TXD1_Pin GPIO_PIN_14 -#define RMII_TXD1_GPIO_Port GPIOG -#define FMC_NBL1_Pin GPIO_PIN_1 -#define FMC_NBL1_GPIO_Port GPIOE -#define FMC_NBL0_Pin GPIO_PIN_0 -#define FMC_NBL0_GPIO_Port GPIOE -#define ARDUINO_SCL_D15_Pin GPIO_PIN_8 -#define ARDUINO_SCL_D15_GPIO_Port GPIOB -#define ARDUINO_D3_Pin GPIO_PIN_4 -#define ARDUINO_D3_GPIO_Port GPIOB -#define SWO_Pin GPIO_PIN_3 -#define SWO_GPIO_Port GPIOB -#define SPDIF_RX0_Pin GPIO_PIN_7 -#define SPDIF_RX0_GPIO_Port GPIOD -#define SDMMC_CK_Pin GPIO_PIN_12 -#define SDMMC_CK_GPIO_Port GPIOC -#define ARDUINO_PWM_D9_Pin GPIO_PIN_15 -#define ARDUINO_PWM_D9_GPIO_Port GPIOA -#define SWCLK_Pin GPIO_PIN_14 -#define SWCLK_GPIO_Port GPIOA -#define SWDIO_Pin GPIO_PIN_13 -#define SWDIO_GPIO_Port GPIOA -#define DCMI_D6_Pin GPIO_PIN_5 -#define DCMI_D6_GPIO_Port GPIOE -#define DCMI_D7_Pin GPIO_PIN_6 -#define DCMI_D7_GPIO_Port GPIOE -#define RMII_TXD0_Pin GPIO_PIN_13 -#define RMII_TXD0_GPIO_Port GPIOG -#define ARDUINO_SDA_D14_Pin GPIO_PIN_9 -#define ARDUINO_SDA_D14_GPIO_Port GPIOB -#define VCP_RX_Pin GPIO_PIN_7 -#define VCP_RX_GPIO_Port GPIOB -#define QSPI_NCS_Pin GPIO_PIN_6 -#define QSPI_NCS_GPIO_Port GPIOB -#define FMC_SDNCAS_Pin GPIO_PIN_15 -#define FMC_SDNCAS_GPIO_Port GPIOG -#define RMII_TX_EN_Pin GPIO_PIN_11 -#define RMII_TX_EN_GPIO_Port GPIOG -#define LCD_B1_Pin GPIO_PIN_13 -#define LCD_B1_GPIO_Port GPIOJ -#define OTG_FS_VBUS_Pin GPIO_PIN_12 -#define OTG_FS_VBUS_GPIO_Port GPIOJ -#define FMC_D2_Pin GPIO_PIN_0 -#define FMC_D2_GPIO_Port GPIOD -#define SDMMC_D3_Pin GPIO_PIN_11 -#define SDMMC_D3_GPIO_Port GPIOC -#define SDMMC_D2_Pin GPIO_PIN_10 -#define SDMMC_D2_GPIO_Port GPIOC -#define OTG_FS_P_Pin GPIO_PIN_12 -#define OTG_FS_P_GPIO_Port GPIOA -#define NC1_Pin GPIO_PIN_8 -#define NC1_GPIO_Port GPIOI -#define SAI2_MCLKA_Pin GPIO_PIN_4 -#define SAI2_MCLKA_GPIO_Port GPIOI -#define LCD_DE_Pin GPIO_PIN_7 -#define LCD_DE_GPIO_Port GPIOK -#define LCD_B7_Pin GPIO_PIN_6 -#define LCD_B7_GPIO_Port GPIOK -#define LCD_B6_Pin GPIO_PIN_5 -#define LCD_B6_GPIO_Port GPIOK -#define LCD_B4_Pin GPIO_PIN_12 -#define LCD_B4_GPIO_Port GPIOG -#define SAI2_SDB_Pin GPIO_PIN_10 -#define SAI2_SDB_GPIO_Port GPIOG -#define LCD_B2_Pin GPIO_PIN_14 -#define LCD_B2_GPIO_Port GPIOJ -#define OTG_FS_PowerSwitchOn_Pin GPIO_PIN_5 -#define OTG_FS_PowerSwitchOn_GPIO_Port GPIOD -#define DCMI_D5_Pin GPIO_PIN_3 -#define DCMI_D5_GPIO_Port GPIOD -#define FMC_D3_Pin GPIO_PIN_1 -#define FMC_D3_GPIO_Port GPIOD -#define ARDUINO_D7_Pin GPIO_PIN_3 -#define ARDUINO_D7_GPIO_Port GPIOI -#define ARDUINO_D7_EXTI_IRQn EXTI3_IRQn -#define ARDUINO_D8_Pin GPIO_PIN_2 -#define ARDUINO_D8_GPIO_Port GPIOI -#define ARDUINO_D8_EXTI_IRQn EXTI2_IRQn -#define OTG_FS_N_Pin GPIO_PIN_11 -#define OTG_FS_N_GPIO_Port GPIOA -#define uSD_Detect_Pin GPIO_PIN_13 -#define uSD_Detect_GPIO_Port GPIOC -#define FMC_A0_Pin GPIO_PIN_0 -#define FMC_A0_GPIO_Port GPIOF -#define SAI2_SCKA_Pin GPIO_PIN_5 -#define SAI2_SCKA_GPIO_Port GPIOI -#define SAI2_FSA_Pin GPIO_PIN_7 -#define SAI2_FSA_GPIO_Port GPIOI -#define LCD_HSYNC_Pin GPIO_PIN_10 -#define LCD_HSYNC_GPIO_Port GPIOI -#define SAI2_SDA_Pin GPIO_PIN_6 -#define SAI2_SDA_GPIO_Port GPIOI -#define LCD_B5_Pin GPIO_PIN_4 -#define LCD_B5_GPIO_Port GPIOK -#define LCD_BL_CTRL_Pin GPIO_PIN_3 -#define LCD_BL_CTRL_GPIO_Port GPIOK -#define DCMI_VSYNC_Pin GPIO_PIN_9 -#define DCMI_VSYNC_GPIO_Port GPIOG -#define LCD_B3_Pin GPIO_PIN_15 -#define LCD_B3_GPIO_Port GPIOJ -#define OTG_FS_OverCurrent_Pin GPIO_PIN_4 -#define OTG_FS_OverCurrent_GPIO_Port GPIOD -#define SDMMC_CMD_Pin GPIO_PIN_2 -#define SDMMC_CMD_GPIO_Port GPIOD -#define TP3_Pin GPIO_PIN_15 -#define TP3_GPIO_Port GPIOH -#define ARDUINO_SCK_D13_Pin GPIO_PIN_1 -#define ARDUINO_SCK_D13_GPIO_Port GPIOI -#define OTG_FS_ID_Pin GPIO_PIN_10 -#define OTG_FS_ID_GPIO_Port GPIOA -#define RCC_OSC32_IN_Pin GPIO_PIN_14 -#define RCC_OSC32_IN_GPIO_Port GPIOC -#define FMC_A1_Pin GPIO_PIN_1 -#define FMC_A1_GPIO_Port GPIOF -#define LCD_DISP_Pin GPIO_PIN_12 -#define LCD_DISP_GPIO_Port GPIOI -#define LCD_VSYNC_Pin GPIO_PIN_9 -#define LCD_VSYNC_GPIO_Port GPIOI -#define DCMI_PWR_EN_Pin GPIO_PIN_13 -#define DCMI_PWR_EN_GPIO_Port GPIOH -#define DCMI_D4_Pin GPIO_PIN_14 -#define DCMI_D4_GPIO_Port GPIOH -#define ARDUINO_PWM_CS_D5_Pin GPIO_PIN_0 -#define ARDUINO_PWM_CS_D5_GPIO_Port GPIOI -#define VCP_TX_Pin GPIO_PIN_9 -#define VCP_TX_GPIO_Port GPIOA -#define RCC_OSC32_OUT_Pin GPIO_PIN_15 -#define RCC_OSC32_OUT_GPIO_Port GPIOC -#define LCD_G6_Pin GPIO_PIN_1 -#define LCD_G6_GPIO_Port GPIOK -#define LCD_G7_Pin GPIO_PIN_2 -#define LCD_G7_GPIO_Port GPIOK -#define ARDUINO_PWM_D10_Pin GPIO_PIN_8 -#define ARDUINO_PWM_D10_GPIO_Port GPIOA -#define OSC_25M_Pin GPIO_PIN_0 -#define OSC_25M_GPIO_Port GPIOH -#define FMC_A2_Pin GPIO_PIN_2 -#define FMC_A2_GPIO_Port GPIOF -#define LCD_INT_Pin GPIO_PIN_13 -#define LCD_INT_GPIO_Port GPIOI -#define LCD_R0_Pin GPIO_PIN_15 -#define LCD_R0_GPIO_Port GPIOI -#define LCD_G4_Pin GPIO_PIN_11 -#define LCD_G4_GPIO_Port GPIOJ -#define LCD_G5_Pin GPIO_PIN_0 -#define LCD_G5_GPIO_Port GPIOK -#define ARDUINO_RX_D0_Pin GPIO_PIN_7 -#define ARDUINO_RX_D0_GPIO_Port GPIOC -#define FMC_A3_Pin GPIO_PIN_3 -#define FMC_A3_GPIO_Port GPIOF -#define LCD_CLK_Pin GPIO_PIN_14 -#define LCD_CLK_GPIO_Port GPIOI -#define LCD_G1_Pin GPIO_PIN_8 -#define LCD_G1_GPIO_Port GPIOJ -#define LCD_G3_Pin GPIO_PIN_10 -#define LCD_G3_GPIO_Port GPIOJ -#define FMC_SDCLK_Pin GPIO_PIN_8 -#define FMC_SDCLK_GPIO_Port GPIOG -#define ARDUINO_TX_D1_Pin GPIO_PIN_6 -#define ARDUINO_TX_D1_GPIO_Port GPIOC -#define FMC_A4_Pin GPIO_PIN_4 -#define FMC_A4_GPIO_Port GPIOF -#define FMC_SDNME_Pin GPIO_PIN_5 -#define FMC_SDNME_GPIO_Port GPIOH -#define FMC_SDNE0_Pin GPIO_PIN_3 -#define FMC_SDNE0_GPIO_Port GPIOH -#define LCD_G0_Pin GPIO_PIN_7 -#define LCD_G0_GPIO_Port GPIOJ -#define LCD_G2_Pin GPIO_PIN_9 -#define LCD_G2_GPIO_Port GPIOJ -#define ARDUINO_D4_Pin GPIO_PIN_7 -#define ARDUINO_D4_GPIO_Port GPIOG -#define ARDUINO_D4_EXTI_IRQn EXTI9_5_IRQn -#define ARDUINO_D2_Pin GPIO_PIN_6 -#define ARDUINO_D2_GPIO_Port GPIOG -#define ARDUINO_D2_EXTI_IRQn EXTI9_5_IRQn -#define ARDUINO_A4_Pin GPIO_PIN_7 -#define ARDUINO_A4_GPIO_Port GPIOF -#define ARDUINO_A5_Pin GPIO_PIN_6 -#define ARDUINO_A5_GPIO_Port GPIOF -#define FMC_A5_Pin GPIO_PIN_5 -#define FMC_A5_GPIO_Port GPIOF -#define NC2_Pin GPIO_PIN_2 -#define NC2_GPIO_Port GPIOH -#define LCD_R7_Pin GPIO_PIN_6 -#define LCD_R7_GPIO_Port GPIOJ -#define FMC_D1_Pin GPIO_PIN_15 -#define FMC_D1_GPIO_Port GPIOD -#define FMC_D15_Pin GPIO_PIN_10 -#define FMC_D15_GPIO_Port GPIOD -#define ARDUINO_A1_Pin GPIO_PIN_10 -#define ARDUINO_A1_GPIO_Port GPIOF -#define ARDUINO_A2_Pin GPIO_PIN_9 -#define ARDUINO_A2_GPIO_Port GPIOF -#define ARDUINO_A3_Pin GPIO_PIN_8 -#define ARDUINO_A3_GPIO_Port GPIOF -#define FMC_SDCKE0_Pin GPIO_PIN_3 -#define FMC_SDCKE0_GPIO_Port GPIOC -#define FMC_D0_Pin GPIO_PIN_14 -#define FMC_D0_GPIO_Port GPIOD -#define FMC_D14_Pin GPIO_PIN_9 -#define FMC_D14_GPIO_Port GPIOD -#define FMC_D13_Pin GPIO_PIN_8 -#define FMC_D13_GPIO_Port GPIOD -#define RMII_MDC_Pin GPIO_PIN_1 -#define RMII_MDC_GPIO_Port GPIOC -#define FMC_A6_Pin GPIO_PIN_12 -#define FMC_A6_GPIO_Port GPIOF -#define FMC_A11_Pin GPIO_PIN_1 -#define FMC_A11_GPIO_Port GPIOG -#define FMC_A9_Pin GPIO_PIN_15 -#define FMC_A9_GPIO_Port GPIOF -#define LCD_R5_Pin GPIO_PIN_4 -#define LCD_R5_GPIO_Port GPIOJ -#define QSPI_D1_Pin GPIO_PIN_12 -#define QSPI_D1_GPIO_Port GPIOD -#define QSPI_D3_Pin GPIO_PIN_13 -#define QSPI_D3_GPIO_Port GPIOD -#define EXT_RST_Pin GPIO_PIN_3 -#define EXT_RST_GPIO_Port GPIOG -#define RMII_RXER_Pin GPIO_PIN_2 -#define RMII_RXER_GPIO_Port GPIOG -#define LCD_R6_Pin GPIO_PIN_5 -#define LCD_R6_GPIO_Port GPIOJ -#define DCMI_D3_Pin GPIO_PIN_12 -#define DCMI_D3_GPIO_Port GPIOH -#define RMII_REF_CLK_Pin GPIO_PIN_1 -#define RMII_REF_CLK_GPIO_Port GPIOA -#define ARDUINO_A0_Pin GPIO_PIN_0 -#define ARDUINO_A0_GPIO_Port GPIOA -#define DCMI_HSYNC_Pin GPIO_PIN_4 -#define DCMI_HSYNC_GPIO_Port GPIOA -#define RMII_RXD0_Pin GPIO_PIN_4 -#define RMII_RXD0_GPIO_Port GPIOC -#define FMC_A7_Pin GPIO_PIN_13 -#define FMC_A7_GPIO_Port GPIOF -#define FMC_A10_Pin GPIO_PIN_0 -#define FMC_A10_GPIO_Port GPIOG -#define LCD_R4_Pin GPIO_PIN_3 -#define LCD_R4_GPIO_Port GPIOJ -#define FMC_D5_Pin GPIO_PIN_8 -#define FMC_D5_GPIO_Port GPIOE -#define QSPI_D0_Pin GPIO_PIN_11 -#define QSPI_D0_GPIO_Port GPIOD -#define FMC_BA1_Pin GPIO_PIN_5 -#define FMC_BA1_GPIO_Port GPIOG -#define FMC_BA0_Pin GPIO_PIN_4 -#define FMC_BA0_GPIO_Port GPIOG -#define LCD_SCL_Pin GPIO_PIN_7 -#define LCD_SCL_GPIO_Port GPIOH -#define DCMI_D0_Pin GPIO_PIN_9 -#define DCMI_D0_GPIO_Port GPIOH -#define DCMI_D2_Pin GPIO_PIN_11 -#define DCMI_D2_GPIO_Port GPIOH -#define RMII_MDIO_Pin GPIO_PIN_2 -#define RMII_MDIO_GPIO_Port GPIOA -#define RMII_RXD1_Pin GPIO_PIN_5 -#define RMII_RXD1_GPIO_Port GPIOC -#define FMC_A8_Pin GPIO_PIN_14 -#define FMC_A8_GPIO_Port GPIOF -#define LCD_R3_Pin GPIO_PIN_2 -#define LCD_R3_GPIO_Port GPIOJ -#define FMC_SDNRAS_Pin GPIO_PIN_11 -#define FMC_SDNRAS_GPIO_Port GPIOF -#define FMC_D6_Pin GPIO_PIN_9 -#define FMC_D6_GPIO_Port GPIOE -#define FMC_D8_Pin GPIO_PIN_11 -#define FMC_D8_GPIO_Port GPIOE -#define FMC_D11_Pin GPIO_PIN_14 -#define FMC_D11_GPIO_Port GPIOE -#define ULPI_D3_Pin GPIO_PIN_10 -#define ULPI_D3_GPIO_Port GPIOB -#define ARDUINO_PWM_D6_Pin GPIO_PIN_6 -#define ARDUINO_PWM_D6_GPIO_Port GPIOH -#define LCD_SDA_Pin GPIO_PIN_8 -#define LCD_SDA_GPIO_Port GPIOH -#define DCMI_D1_Pin GPIO_PIN_10 -#define DCMI_D1_GPIO_Port GPIOH -#define RMII_CRS_DV_Pin GPIO_PIN_7 -#define RMII_CRS_DV_GPIO_Port GPIOA -#define LCD_R1_Pin GPIO_PIN_0 -#define LCD_R1_GPIO_Port GPIOJ -#define LCD_R2_Pin GPIO_PIN_1 -#define LCD_R2_GPIO_Port GPIOJ -#define FMC_D4_Pin GPIO_PIN_7 -#define FMC_D4_GPIO_Port GPIOE -#define FMC_D7_Pin GPIO_PIN_10 -#define FMC_D7_GPIO_Port GPIOE -#define FMC_D9_Pin GPIO_PIN_12 -#define FMC_D9_GPIO_Port GPIOE -#define FMC_D12_Pin GPIO_PIN_15 -#define FMC_D12_GPIO_Port GPIOE -#define FMC_D10_Pin GPIO_PIN_13 -#define FMC_D10_GPIO_Port GPIOE -#define ARDUINO_MISO_D12_Pin GPIO_PIN_14 -#define ARDUINO_MISO_D12_GPIO_Port GPIOB -#define ARDUINO_MOSI_PWM_D11_Pin GPIO_PIN_15 -#define ARDUINO_MOSI_PWM_D11_GPIO_Port GPIOB -/* USER CODE BEGIN Private defines */ - -/* USER CODE END Private defines */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MAIN_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/stm37f750-dk/port_conf.h b/src/port_stm32f7/stm37f750-dk/port_conf.h index 19778344..985cb98b 100644 --- a/src/port_stm32f7/stm37f750-dk/port_conf.h +++ b/src/port_stm32f7/stm37f750-dk/port_conf.h @@ -8,7 +8,6 @@ #include "stm32f7508_discovery_lcd.h" #include "stm32f7508_discovery_sd.h" #include "stm32f7508_discovery_sdram.h" -#include "main.h" /* PIN MAPPING - Teensy uses an Arduino Backend, we just assign the enum to the Arduino Pin number USB64_PIN_MAX must be the largest pin number in the list add one*/ diff --git a/src/port_stm32f7/stm37f750-dk/usbh_stm32.cpp b/src/port_stm32f7/stm37f750-dk/usbh_stm32.cpp index 89b47fe0..8230cdec 100644 --- a/src/port_stm32f7/stm37f750-dk/usbh_stm32.cpp +++ b/src/port_stm32f7/stm37f750-dk/usbh_stm32.cpp @@ -23,12 +23,12 @@ void usbh_dev_init() GPIO_InitTypeDef GPIO_InitStruct; //Turn on 5V output - GPIO_InitStruct.Pin = OTG_FS_PowerSwitchOn_Pin; + GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - HAL_GPIO_Init(OTG_FS_PowerSwitchOn_GPIO_Port, &GPIO_InitStruct); - HAL_GPIO_WritePin(OTG_FS_PowerSwitchOn_GPIO_Port, OTG_FS_PowerSwitchOn_Pin, GPIO_PIN_RESET); + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_RESET); //Setup USB data pins GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12; diff --git a/src/port_stm32f7/stm37f769-dk/main.h b/src/port_stm32f7/stm37f769-dk/main.h deleted file mode 100644 index 491b07cf..00000000 --- a/src/port_stm32f7/stm37f769-dk/main.h +++ /dev/null @@ -1,377 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file : main.h - * @brief : Header for main.c file. - * This file contains the common defines of the application. - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2021 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __MAIN_H -#define __MAIN_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f7xx_hal.h" - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -/* Exported types ------------------------------------------------------------*/ -/* USER CODE BEGIN ET */ - -/* USER CODE END ET */ - -/* Exported constants --------------------------------------------------------*/ -/* USER CODE BEGIN EC */ - -/* USER CODE END EC */ - -/* Exported macro ------------------------------------------------------------*/ -/* USER CODE BEGIN EM */ - -/* USER CODE END EM */ - -void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim); - -/* Exported functions prototypes ---------------------------------------------*/ -void Error_Handler(void); - -/* USER CODE BEGIN EFP */ - -/* USER CODE END EFP */ - -/* Private defines -----------------------------------------------------------*/ -#define LCD_B0_Pin GPIO_PIN_4 -#define LCD_B0_GPIO_Port GPIOE -#define OTG_HS_OverCurrent_Pin GPIO_PIN_3 -#define OTG_HS_OverCurrent_GPIO_Port GPIOE -#define QSPI_D2_Pin GPIO_PIN_2 -#define QSPI_D2_GPIO_Port GPIOE -#define RMII_TXD1_Pin GPIO_PIN_14 -#define RMII_TXD1_GPIO_Port GPIOG -#define FMC_NBL1_Pin GPIO_PIN_1 -#define FMC_NBL1_GPIO_Port GPIOE -#define FMC_NBL0_Pin GPIO_PIN_0 -#define FMC_NBL0_GPIO_Port GPIOE -#define ARDUINO_SCL_D15_Pin GPIO_PIN_8 -#define ARDUINO_SCL_D15_GPIO_Port GPIOB -#define ARDUINO_D3_Pin GPIO_PIN_4 -#define ARDUINO_D3_GPIO_Port GPIOB -#define SWO_Pin GPIO_PIN_3 -#define SWO_GPIO_Port GPIOB -#define SPDIF_RX0_Pin GPIO_PIN_7 -#define SPDIF_RX0_GPIO_Port GPIOD -#define SDMMC_CK_Pin GPIO_PIN_12 -#define SDMMC_CK_GPIO_Port GPIOC -#define ARDUINO_PWM_D9_Pin GPIO_PIN_15 -#define ARDUINO_PWM_D9_GPIO_Port GPIOA -#define SWCLK_Pin GPIO_PIN_14 -#define SWCLK_GPIO_Port GPIOA -#define SWDIO_Pin GPIO_PIN_13 -#define SWDIO_GPIO_Port GPIOA -#define DCMI_D6_Pin GPIO_PIN_5 -#define DCMI_D6_GPIO_Port GPIOE -#define DCMI_D7_Pin GPIO_PIN_6 -#define DCMI_D7_GPIO_Port GPIOE -#define RMII_TXD0_Pin GPIO_PIN_13 -#define RMII_TXD0_GPIO_Port GPIOG -#define ARDUINO_SDA_D14_Pin GPIO_PIN_9 -#define ARDUINO_SDA_D14_GPIO_Port GPIOB -#define VCP_RX_Pin GPIO_PIN_7 -#define VCP_RX_GPIO_Port GPIOB -#define QSPI_NCS_Pin GPIO_PIN_6 -#define QSPI_NCS_GPIO_Port GPIOB -#define FMC_SDNCAS_Pin GPIO_PIN_15 -#define FMC_SDNCAS_GPIO_Port GPIOG -#define RMII_TX_EN_Pin GPIO_PIN_11 -#define RMII_TX_EN_GPIO_Port GPIOG -#define LCD_B1_Pin GPIO_PIN_13 -#define LCD_B1_GPIO_Port GPIOJ -#define OTG_FS_VBUS_Pin GPIO_PIN_12 -#define OTG_FS_VBUS_GPIO_Port GPIOJ -#define FMC_D2_Pin GPIO_PIN_0 -#define FMC_D2_GPIO_Port GPIOD -#define SDMMC_D3_Pin GPIO_PIN_11 -#define SDMMC_D3_GPIO_Port GPIOC -#define SDMMC_D2_Pin GPIO_PIN_10 -#define SDMMC_D2_GPIO_Port GPIOC -#define OTG_FS_P_Pin GPIO_PIN_12 -#define OTG_FS_P_GPIO_Port GPIOA -#define NC1_Pin GPIO_PIN_8 -#define NC1_GPIO_Port GPIOI -#define SAI2_MCLKA_Pin GPIO_PIN_4 -#define SAI2_MCLKA_GPIO_Port GPIOI -#define LCD_DE_Pin GPIO_PIN_7 -#define LCD_DE_GPIO_Port GPIOK -#define LCD_B7_Pin GPIO_PIN_6 -#define LCD_B7_GPIO_Port GPIOK -#define LCD_B6_Pin GPIO_PIN_5 -#define LCD_B6_GPIO_Port GPIOK -#define LCD_B4_Pin GPIO_PIN_12 -#define LCD_B4_GPIO_Port GPIOG -#define SAI2_SDB_Pin GPIO_PIN_10 -#define SAI2_SDB_GPIO_Port GPIOG -#define LCD_B2_Pin GPIO_PIN_14 -#define LCD_B2_GPIO_Port GPIOJ -#define OTG_FS_PowerSwitchOn_Pin GPIO_PIN_5 -#define OTG_FS_PowerSwitchOn_GPIO_Port GPIOD -#define DCMI_D5_Pin GPIO_PIN_3 -#define DCMI_D5_GPIO_Port GPIOD -#define FMC_D3_Pin GPIO_PIN_1 -#define FMC_D3_GPIO_Port GPIOD -#define ARDUINO_D7_Pin GPIO_PIN_3 -#define ARDUINO_D7_GPIO_Port GPIOI -#define ARDUINO_D7_EXTI_IRQn EXTI3_IRQn -#define ARDUINO_D8_Pin GPIO_PIN_2 -#define ARDUINO_D8_GPIO_Port GPIOI -#define ARDUINO_D8_EXTI_IRQn EXTI2_IRQn -#define OTG_FS_N_Pin GPIO_PIN_11 -#define OTG_FS_N_GPIO_Port GPIOA -#define uSD_Detect_Pin GPIO_PIN_13 -#define uSD_Detect_GPIO_Port GPIOC -#define FMC_A0_Pin GPIO_PIN_0 -#define FMC_A0_GPIO_Port GPIOF -#define SAI2_SCKA_Pin GPIO_PIN_5 -#define SAI2_SCKA_GPIO_Port GPIOI -#define SAI2_FSA_Pin GPIO_PIN_7 -#define SAI2_FSA_GPIO_Port GPIOI -#define LCD_HSYNC_Pin GPIO_PIN_10 -#define LCD_HSYNC_GPIO_Port GPIOI -#define SAI2_SDA_Pin GPIO_PIN_6 -#define SAI2_SDA_GPIO_Port GPIOI -#define LCD_B5_Pin GPIO_PIN_4 -#define LCD_B5_GPIO_Port GPIOK -#define LCD_BL_CTRL_Pin GPIO_PIN_3 -#define LCD_BL_CTRL_GPIO_Port GPIOK -#define DCMI_VSYNC_Pin GPIO_PIN_9 -#define DCMI_VSYNC_GPIO_Port GPIOG -#define LCD_B3_Pin GPIO_PIN_15 -#define LCD_B3_GPIO_Port GPIOJ -#define OTG_FS_OverCurrent_Pin GPIO_PIN_4 -#define OTG_FS_OverCurrent_GPIO_Port GPIOD -#define SDMMC_CMD_Pin GPIO_PIN_2 -#define SDMMC_CMD_GPIO_Port GPIOD -#define TP3_Pin GPIO_PIN_15 -#define TP3_GPIO_Port GPIOH -#define ARDUINO_SCK_D13_Pin GPIO_PIN_1 -#define ARDUINO_SCK_D13_GPIO_Port GPIOI -#define OTG_FS_ID_Pin GPIO_PIN_10 -#define OTG_FS_ID_GPIO_Port GPIOA -#define RCC_OSC32_IN_Pin GPIO_PIN_14 -#define RCC_OSC32_IN_GPIO_Port GPIOC -#define FMC_A1_Pin GPIO_PIN_1 -#define FMC_A1_GPIO_Port GPIOF -#define LCD_DISP_Pin GPIO_PIN_12 -#define LCD_DISP_GPIO_Port GPIOI -#define LCD_VSYNC_Pin GPIO_PIN_9 -#define LCD_VSYNC_GPIO_Port GPIOI -#define DCMI_PWR_EN_Pin GPIO_PIN_13 -#define DCMI_PWR_EN_GPIO_Port GPIOH -#define DCMI_D4_Pin GPIO_PIN_14 -#define DCMI_D4_GPIO_Port GPIOH -#define ARDUINO_PWM_CS_D5_Pin GPIO_PIN_0 -#define ARDUINO_PWM_CS_D5_GPIO_Port GPIOI -#define VCP_TX_Pin GPIO_PIN_9 -#define VCP_TX_GPIO_Port GPIOA -#define RCC_OSC32_OUT_Pin GPIO_PIN_15 -#define RCC_OSC32_OUT_GPIO_Port GPIOC -#define LCD_G6_Pin GPIO_PIN_1 -#define LCD_G6_GPIO_Port GPIOK -#define LCD_G7_Pin GPIO_PIN_2 -#define LCD_G7_GPIO_Port GPIOK -#define ARDUINO_PWM_D10_Pin GPIO_PIN_8 -#define ARDUINO_PWM_D10_GPIO_Port GPIOA -#define OSC_25M_Pin GPIO_PIN_0 -#define OSC_25M_GPIO_Port GPIOH -#define FMC_A2_Pin GPIO_PIN_2 -#define FMC_A2_GPIO_Port GPIOF -#define LCD_INT_Pin GPIO_PIN_13 -#define LCD_INT_GPIO_Port GPIOI -#define LCD_R0_Pin GPIO_PIN_15 -#define LCD_R0_GPIO_Port GPIOI -#define LCD_G4_Pin GPIO_PIN_11 -#define LCD_G4_GPIO_Port GPIOJ -#define LCD_G5_Pin GPIO_PIN_0 -#define LCD_G5_GPIO_Port GPIOK -#define ARDUINO_RX_D0_Pin GPIO_PIN_7 -#define ARDUINO_RX_D0_GPIO_Port GPIOC -#define FMC_A3_Pin GPIO_PIN_3 -#define FMC_A3_GPIO_Port GPIOF -#define LCD_CLK_Pin GPIO_PIN_14 -#define LCD_CLK_GPIO_Port GPIOI -#define LCD_G1_Pin GPIO_PIN_8 -#define LCD_G1_GPIO_Port GPIOJ -#define LCD_G3_Pin GPIO_PIN_10 -#define LCD_G3_GPIO_Port GPIOJ -#define FMC_SDCLK_Pin GPIO_PIN_8 -#define FMC_SDCLK_GPIO_Port GPIOG -#define ARDUINO_TX_D1_Pin GPIO_PIN_6 -#define ARDUINO_TX_D1_GPIO_Port GPIOC -#define FMC_A4_Pin GPIO_PIN_4 -#define FMC_A4_GPIO_Port GPIOF -#define FMC_SDNME_Pin GPIO_PIN_5 -#define FMC_SDNME_GPIO_Port GPIOH -#define FMC_SDNE0_Pin GPIO_PIN_3 -#define FMC_SDNE0_GPIO_Port GPIOH -#define LCD_G0_Pin GPIO_PIN_7 -#define LCD_G0_GPIO_Port GPIOJ -#define LCD_G2_Pin GPIO_PIN_9 -#define LCD_G2_GPIO_Port GPIOJ -#define ARDUINO_D4_Pin GPIO_PIN_7 -#define ARDUINO_D4_GPIO_Port GPIOG -#define ARDUINO_D4_EXTI_IRQn EXTI9_5_IRQn -#define ARDUINO_D2_Pin GPIO_PIN_6 -#define ARDUINO_D2_GPIO_Port GPIOG -#define ARDUINO_D2_EXTI_IRQn EXTI9_5_IRQn -#define ARDUINO_A4_Pin GPIO_PIN_7 -#define ARDUINO_A4_GPIO_Port GPIOF -#define ARDUINO_A5_Pin GPIO_PIN_6 -#define ARDUINO_A5_GPIO_Port GPIOF -#define FMC_A5_Pin GPIO_PIN_5 -#define FMC_A5_GPIO_Port GPIOF -#define NC2_Pin GPIO_PIN_2 -#define NC2_GPIO_Port GPIOH -#define LCD_R7_Pin GPIO_PIN_6 -#define LCD_R7_GPIO_Port GPIOJ -#define FMC_D1_Pin GPIO_PIN_15 -#define FMC_D1_GPIO_Port GPIOD -#define FMC_D15_Pin GPIO_PIN_10 -#define FMC_D15_GPIO_Port GPIOD -#define ARDUINO_A1_Pin GPIO_PIN_10 -#define ARDUINO_A1_GPIO_Port GPIOF -#define ARDUINO_A2_Pin GPIO_PIN_9 -#define ARDUINO_A2_GPIO_Port GPIOF -#define ARDUINO_A3_Pin GPIO_PIN_8 -#define ARDUINO_A3_GPIO_Port GPIOF -#define FMC_SDCKE0_Pin GPIO_PIN_3 -#define FMC_SDCKE0_GPIO_Port GPIOC -#define FMC_D0_Pin GPIO_PIN_14 -#define FMC_D0_GPIO_Port GPIOD -#define FMC_D14_Pin GPIO_PIN_9 -#define FMC_D14_GPIO_Port GPIOD -#define FMC_D13_Pin GPIO_PIN_8 -#define FMC_D13_GPIO_Port GPIOD -#define RMII_MDC_Pin GPIO_PIN_1 -#define RMII_MDC_GPIO_Port GPIOC -#define FMC_A6_Pin GPIO_PIN_12 -#define FMC_A6_GPIO_Port GPIOF -#define FMC_A11_Pin GPIO_PIN_1 -#define FMC_A11_GPIO_Port GPIOG -#define FMC_A9_Pin GPIO_PIN_15 -#define FMC_A9_GPIO_Port GPIOF -#define LCD_R5_Pin GPIO_PIN_4 -#define LCD_R5_GPIO_Port GPIOJ -#define QSPI_D1_Pin GPIO_PIN_12 -#define QSPI_D1_GPIO_Port GPIOD -#define QSPI_D3_Pin GPIO_PIN_13 -#define QSPI_D3_GPIO_Port GPIOD -#define EXT_RST_Pin GPIO_PIN_3 -#define EXT_RST_GPIO_Port GPIOG -#define RMII_RXER_Pin GPIO_PIN_2 -#define RMII_RXER_GPIO_Port GPIOG -#define LCD_R6_Pin GPIO_PIN_5 -#define LCD_R6_GPIO_Port GPIOJ -#define DCMI_D3_Pin GPIO_PIN_12 -#define DCMI_D3_GPIO_Port GPIOH -#define RMII_REF_CLK_Pin GPIO_PIN_1 -#define RMII_REF_CLK_GPIO_Port GPIOA -#define ARDUINO_A0_Pin GPIO_PIN_0 -#define ARDUINO_A0_GPIO_Port GPIOA -#define DCMI_HSYNC_Pin GPIO_PIN_4 -#define DCMI_HSYNC_GPIO_Port GPIOA -#define RMII_RXD0_Pin GPIO_PIN_4 -#define RMII_RXD0_GPIO_Port GPIOC -#define FMC_A7_Pin GPIO_PIN_13 -#define FMC_A7_GPIO_Port GPIOF -#define FMC_A10_Pin GPIO_PIN_0 -#define FMC_A10_GPIO_Port GPIOG -#define LCD_R4_Pin GPIO_PIN_3 -#define LCD_R4_GPIO_Port GPIOJ -#define FMC_D5_Pin GPIO_PIN_8 -#define FMC_D5_GPIO_Port GPIOE -#define QSPI_D0_Pin GPIO_PIN_11 -#define QSPI_D0_GPIO_Port GPIOD -#define FMC_BA1_Pin GPIO_PIN_5 -#define FMC_BA1_GPIO_Port GPIOG -#define FMC_BA0_Pin GPIO_PIN_4 -#define FMC_BA0_GPIO_Port GPIOG -#define LCD_SCL_Pin GPIO_PIN_7 -#define LCD_SCL_GPIO_Port GPIOH -#define DCMI_D0_Pin GPIO_PIN_9 -#define DCMI_D0_GPIO_Port GPIOH -#define DCMI_D2_Pin GPIO_PIN_11 -#define DCMI_D2_GPIO_Port GPIOH -#define RMII_MDIO_Pin GPIO_PIN_2 -#define RMII_MDIO_GPIO_Port GPIOA -#define RMII_RXD1_Pin GPIO_PIN_5 -#define RMII_RXD1_GPIO_Port GPIOC -#define FMC_A8_Pin GPIO_PIN_14 -#define FMC_A8_GPIO_Port GPIOF -#define LCD_R3_Pin GPIO_PIN_2 -#define LCD_R3_GPIO_Port GPIOJ -#define FMC_SDNRAS_Pin GPIO_PIN_11 -#define FMC_SDNRAS_GPIO_Port GPIOF -#define FMC_D6_Pin GPIO_PIN_9 -#define FMC_D6_GPIO_Port GPIOE -#define FMC_D8_Pin GPIO_PIN_11 -#define FMC_D8_GPIO_Port GPIOE -#define FMC_D11_Pin GPIO_PIN_14 -#define FMC_D11_GPIO_Port GPIOE -#define ULPI_D3_Pin GPIO_PIN_10 -#define ULPI_D3_GPIO_Port GPIOB -#define ARDUINO_PWM_D6_Pin GPIO_PIN_6 -#define ARDUINO_PWM_D6_GPIO_Port GPIOH -#define LCD_SDA_Pin GPIO_PIN_8 -#define LCD_SDA_GPIO_Port GPIOH -#define DCMI_D1_Pin GPIO_PIN_10 -#define DCMI_D1_GPIO_Port GPIOH -#define RMII_CRS_DV_Pin GPIO_PIN_7 -#define RMII_CRS_DV_GPIO_Port GPIOA -#define LCD_R1_Pin GPIO_PIN_0 -#define LCD_R1_GPIO_Port GPIOJ -#define LCD_R2_Pin GPIO_PIN_1 -#define LCD_R2_GPIO_Port GPIOJ -#define FMC_D4_Pin GPIO_PIN_7 -#define FMC_D4_GPIO_Port GPIOE -#define FMC_D7_Pin GPIO_PIN_10 -#define FMC_D7_GPIO_Port GPIOE -#define FMC_D9_Pin GPIO_PIN_12 -#define FMC_D9_GPIO_Port GPIOE -#define FMC_D12_Pin GPIO_PIN_15 -#define FMC_D12_GPIO_Port GPIOE -#define FMC_D10_Pin GPIO_PIN_13 -#define FMC_D10_GPIO_Port GPIOE -#define ARDUINO_MISO_D12_Pin GPIO_PIN_14 -#define ARDUINO_MISO_D12_GPIO_Port GPIOB -#define ARDUINO_MOSI_PWM_D11_Pin GPIO_PIN_15 -#define ARDUINO_MOSI_PWM_D11_GPIO_Port GPIOB -/* USER CODE BEGIN Private defines */ - -/* USER CODE END Private defines */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MAIN_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/port_stm32f7/stm37f769-dk/port_conf.h b/src/port_stm32f7/stm37f769-dk/port_conf.h index 08deb775..cca7065b 100644 --- a/src/port_stm32f7/stm37f769-dk/port_conf.h +++ b/src/port_stm32f7/stm37f769-dk/port_conf.h @@ -8,7 +8,6 @@ #include "stm32f769i_discovery_lcd.h" #include "stm32f769i_discovery_sd.h" #include "stm32f769i_discovery_sdram.h" -#include "main.h" /* PIN MAPPING - Teensy uses an Arduino Backend, we just assign the enum to the Arduino Pin number USB64_PIN_MAX must be the largest pin number in the list add one*/ diff --git a/src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp b/src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp index 52e3fb62..9f567456 100644 --- a/src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp +++ b/src/port_stm32f7/stm37f769-dk/usbh_stm32.cpp @@ -23,6 +23,8 @@ extern "C" void OTG_HS_IRQHandler(void) #define ULPI_D2_GPIO_Port GPIOB #define ULPI_D1_Pin GPIO_PIN_0 #define ULPI_D1_GPIO_Port GPIOB +#define ULPI_D3_Pin GPIO_PIN_10 +#define ULPI_D3_GPIO_Port GPIOB #define ULPI_D4_Pin GPIO_PIN_11 #define ULPI_D4_GPIO_Port GPIOB #define ULPI_D6_Pin GPIO_PIN_13 From 879ebb6a61669118295b0eb339dbc9afa40ffa54 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 18 Jan 2022 08:04:05 +1030 Subject: [PATCH 109/121] N64: Add ED64 game identifier packet --- src/n64/n64_controller.c | 53 +- src/n64/n64_controller.h | 1804 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 1856 insertions(+), 1 deletion(-) diff --git a/src/n64/n64_controller.c b/src/n64/n64_controller.c index ab1db998..0a51b0d8 100644 --- a/src/n64/n64_controller.c +++ b/src/n64/n64_controller.c @@ -20,6 +20,35 @@ static uint8_t n64_cont_with_peri[] = {0x05, 0x00, 0x01}; static uint8_t n64_cont_no_peri[] = {0x05, 0x00, 0x02}; static uint8_t n64_cont_crc_error[] = {0x05, 0x00, 0x04}; +//Only works with compatible ED64 flashcarts +static n64_game_t current_game; +const char *n64_get_current_game() +{ + if (current_game.crc_hi == 0) + { + return ""; + } + if (current_game.name != NULL) + { + return current_game.name; + }; + //Reverse the CRC for comparison + uint32_t __crc = (current_game.crc_hi >> 24 & 0xFF) << 0 | + (current_game.crc_hi >> 16 & 0xFF) << 8 | + (current_game.crc_hi >> 8 & 0xFF) << 16 | + (current_game.crc_hi >> 0 & 0xFF) << 24; + + for (int i = 0; i < (sizeof(game_crc_lookup) / sizeof(n64_game_crc_lookup_t)); i++) + { + if (game_crc_lookup[i].crc_hi == __crc) + { + current_game.name = game_crc_lookup[i].name; + return current_game.name; + } + } + return ""; +} + void n64_subsystem_init(n64_input_dev_t *in_dev) { // INITIALISE THE N64 STRUCTS // @@ -45,6 +74,8 @@ void n64_subsystem_init(n64_input_dev_t *in_dev) (i == 3) ? N64_CONTROLLER_4_PIN : -1; } + memset(¤t_game, 0, sizeof(current_game)); + //Setup the Controller pin IO mapping and interrupts n64hal_hs_tick_init(); } @@ -226,9 +257,11 @@ void n64_controller_hande_new_edge(n64_input_dev_t *cont) break; case N64_PERI_READ: case N64_PERI_WRITE: + case N64_ED64_GAMEID: cont->peri_access = 1; break; default: + debug_print_n64("[N64] Unknown command %02x\n", cont->data_buffer[N64_COMMAND_POS]); cont->peri_access = 0; n64_reset_stream(cont); break; @@ -259,8 +292,26 @@ void n64_controller_hande_new_edge(n64_input_dev_t *cont) n64_reset_stream(cont); } + //Ref https://gitlab.com/pixelfx-public/n64-game-id + //ED64 sends a 10 byte packet on game launch which contains the game CRC, ROM type and country code + if (cont->peri_access == 1 && (cont->data_buffer[N64_COMMAND_POS] == N64_ED64_GAMEID) && cont->current_byte == 1 /*Command byte*/ + 10) + { + n64_game_t *_game = (n64_game_t *)&cont->data_buffer[1]; + current_game.crc_hi = _game->crc_hi; + current_game.crc_low = _game->crc_low; + current_game.media_format = _game->media_format; + current_game.country_code = _game->country_code; + current_game.name = NULL; + debug_print_n64("[N64] ED64 Packet received... Booting Game ...\n"); + debug_print_n64(" CRC High: %08x Low: %08x\n", current_game.crc_hi, current_game.crc_low); + debug_print_n64(" Media Format: %02x\n", current_game.media_format); + debug_print_n64(" Country Code: %02x\n", current_game.country_code); + cont->peri_access = 0; + n64_reset_stream(cont); + } + //If we are accessing the peripheral bus, let's handle that - if (cont->peri_access == 1) + else if (cont->peri_access == 1) { uint16_t peri_address = (cont->data_buffer[N64_ADDRESS_MSB_POS] << 8 | cont->data_buffer[N64_ADDRESS_LSB_POS]); diff --git a/src/n64/n64_controller.h b/src/n64/n64_controller.h index 5342ed8d..f6c45c62 100644 --- a/src/n64/n64_controller.h +++ b/src/n64/n64_controller.h @@ -66,6 +66,22 @@ typedef struct usb64_pin_t pin; //What pin is this controller connected to } n64_input_dev_t; +typedef struct +{ + uint32_t crc_hi; + uint32_t crc_low; + uint8_t media_format; + uint8_t country_code; + const char *name; +} n64_game_t; + +typedef struct +{ + uint32_t crc_hi; + uint32_t crc_low; + const char *name; +} n64_game_crc_lookup_t; + //N64 JOYBUS #define N64_IDENTIFY 0x00 #define N64_CONTROLLER_STATUS 0x01 @@ -73,6 +89,7 @@ typedef struct #define N64_PERI_WRITE 0x03 #define N64_CONTROLLER_RESET 0xFF #define N64_RANDNET_REQ 0x13 +#define N64_ED64_GAMEID 0x1D #define N64_COMMAND_POS 0 #define N64_ADDRESS_MSB_POS 1 #define N64_ADDRESS_LSB_POS 2 @@ -115,6 +132,1793 @@ typedef struct void n64_subsystem_init(n64_input_dev_t *in_dev); void n64_controller_hande_new_edge(n64_input_dev_t *cont); +//Only works with compatible ED64 flashcarts +const char *n64_get_current_game(); + +static const FLASHMEM n64_game_crc_lookup_t game_crc_lookup[] = { +{0x3B941695, 0xF90A5EEB, +"007 - The World is Not Enough (E) (M3)"}, +{0x033F4C13, 0x319EE7A7, +"007 - The World is Not Enough (U)"}, +{0x58FD3F25, 0xD92EAA8D, +"1080 Snowboarding (E) [!]"}, +{0x1FBAF161, 0x2C1C54F1, +"1080 Snowboarding (JU) [!]"}, +{0xABA51D09, 0xC668BAD9, +"40 Winks (E) (M3) (Beta)"}, +{0xB98BA456, 0x5B2B76AF, +"64 de Hakken!! Tamagotchi Minna de Tamagotchi World (J)"}, +{0x9C961069, 0xF5EA488D, +"64 Oozumou (J)"}, +{0x85C18B16, 0xDF9622AF, +"64 Oozumou 2 (J)"}, +{0x7A6081FC, 0xFF8F7A78, +"64 Trump Collection - Alice no Wakuwaku Trump World (J) [!]"}, +{0x8F12C096, 0x45DC17E1, +"A Bug's Life (E) [!]"}, +{0x2B38AEC0, 0x6350B810, +"A Bug's Life (F) [!]"}, +{0xDFF227D9, 0x0D4D8169, +"A Bug's Life (G) [!]"}, +{0xF63B89CE, 0x4582D57D, +"A Bug's Life (I)"}, +{0x82DC04FD, 0xCF2D82F4, +"A Bug's Life (U) [!]"}, +{0x62F6BE95, 0xF102D6D6, +"Aerofighter's Assault (E) [!]"}, +{0x1B598BF1, 0xECA29B45, +"Aerofighter's Assault (U) [!]"}, +{0xD83045C8, 0xF29D3A36, +"AeroGauge (E) [!]"}, +{0xB00903C9, 0x3916C146, +"AeroGauge - Kiosk (J) (V1.0)"}, +{0x80F41131, 0x384645F6, +"AeroGauge (J) (V1.1) [!]"}, +{0xAEBE463E, 0xCC71464B, +"AeroGauge (U) [!]"}, +{0x8CC182A6, 0xC2D0CAB0, +"AI Shogi 3 (J) [!]"}, +{0x2DC4FFCC, 0xC8FF5A21, +"Aidyn Chronicles - The First Mage (E) [!]"}, +{0xE6A95A4F, 0xBAD2EA23, +"Aidyn Chronicles - The First Mage (U) [!] (V1.0)"}, +{0x112051D2, 0x68BEF8AC, +"Aidyn Chronicles - The First Mage (U) [!] (V1.1)"}, +{0x27C425D0, 0x8C2D99C1, +"Airboarder 64 (E) [!]"}, +{0x6C45B60C, 0xDCE50E30, +"Airboarder 64 (J) [!]"}, +{0xB6951A94, 0x63C849AF, +"Akumajou Dracula Mokushiroku - Real Action Adventure (J) [!]"}, +{0xA5533106, 0xB9F25E5B, +"Akumajou Dracula Mokushiroku Gaiden-Legend of Cornell (J) [!]"}, +{0xDFD784AD, 0xAE426603, +"All Star Tennis '99 (E) [!]"}, +{0xE185E291, 0x4E50766D, +"All Star Tennis '99 (U) [!]"}, +{0x67D20729, 0xF696774C, +"All Star! Dairantou Smash Brothers (J) [!]"}, +{0xA19F8089, 0x77884B51, +"All-Star Baseball 2000 (E) [!]"}, +{0x5E547A4D, 0x90E60795, +"All-Star Baseball 2000 (U) [!]"}, +{0x5446C6EF, 0xE18E47BB, +"All-Star Baseball 2001 (U) [!]"}, +{0xD9EDD54D, 0x6BB8E274, +"All-Star Baseball 99 (E) [!]"}, +{0xC43E23A7, 0x40B1681A, +"All-Star Baseball 99 (U) [!]"}, +{0x3CC77150, 0x21CDB987, +"Armorines - Project S.W.A.R.M. (E) [!]"}, +{0xC0F6DB17, 0x80E0D532, +"Armorines - Project S.W.A.R.M. (G) [!]"}, +{0x1FB5D932, 0x3BA9481B, +"Armorines - Project S.W.A.R.M. (U) [!]"}, +{0x4C52BBB2, 0xCEAB0F6B, +"Army Men - Air Combat (U) [!]"}, +{0xB210DF19, 0x98B58D1A, +"Army Men - Sarge's Heroes (E) [!]"}, +{0x862C0657, 0x8DFD896D, +"Army Men - Sarge's Heroes (U) [!]"}, +{0xB20F73B6, 0x2975FC34, +"Army Men - Sarge's Heroes 2 (U) [!]"}, +{0xD1F7D8AB, 0x293B0446, +"Asteroids Hyper 64 (U) [!]"}, +{0xFC7797BF, 0x4A95E83C, +"Automobili Lamborghini (E) [!]"}, +{0x41B25DC4, 0x1B726786, +"Automobili Lamborghini (U) [!]"}, +{0xE340A49C, 0x74318D41, +"Baku Bomberman (J) [!]"}, +{0xE73C7C4F, 0xAF93B838, +"Baku Bomberman 2 (J) [!]"}, +{0xDF98B95D, 0x58840978, +"Bakuretsu Muteki Bangaioh (J) [!]"}, +{0x88CF980A, 0x8ED52EB5, +"Bakushou Jinsei 64 - Mezase! Resort Ou (J) [!]"}, +{0x5168D520, 0xCA5FCD0D, +"Banjo to Kazooie no Dai Bouken (J) [!]"}, +{0x514B6900, 0xB4B19881, +"Banjo to Kazooie no Dai Bouken 2 (J) [!]"}, +{0x733FCCB1, 0x444892F9, +"Banjo-Kazooie (E) [!]"}, +{0xA4BF9306, 0xBF0CDFD1, +"Banjo-Kazooie (U) [!]"}, +{0x155B7CDF, 0xF0DA7325, +"Banjo-Tooie (A) [!]"}, +{0xC9176D39, 0xEA4779D1, +"Banjo-Tooie (E) [!]"}, +{0xC2E9AA9A, 0x475D70AA, +"Banjo-Tooie (U) [!]"}, +{0xB088FBB4, 0x441E4B1D, +"Bass Hunter 64 (E) [!]"}, +{0xD76333AC, 0x0CB6219D, +"Bass Rush - Ecogear Powerworm Championship (J)"}, +{0xD137A2CA, 0x62B65053, +"Bass Tsuri No. 1 - Shigesato Itoi's Bass Fishing (J) [!]"}, +{0xBCFACCAA, 0xB814D8EF, +"Bassmasters 2000 (U) [!]"}, +{0x259F7F84, 0x7C9EED26, +"Batman of the Future - Return of the Joker (E) [!]"}, +{0x204489C1, 0x1286CF2B, +"Batman Beyond - Return of the Joker (U) [!]"}, +{0x0CAD17E6, 0x71A5B797, +"BattleTanx - Global Assault (E) [!]"}, +{0x75A4E247, 0x6008963D, +"BattleTanx - Global Assault (U) [!]"}, +{0x6AA4DDE7, 0xE3E2F4E7, +"BattleTanx (U) [!]"}, +{0x55D4C4CE, 0x7753C78A, +"Battlezone - Rise of the Black Dogs (U) [!]"}, +{0x91691C3D, 0xF4AC5B4D, +"Beast Wars Metals (J) [!]"}, +{0x4D79D316, 0xE8501B33, +"Beast Wars Transmetal (U) [!]"}, +{0xA1B64A61, 0xD014940B, +"Beetle Adventure Racing! (E) [!]"}, +{0x9C7318D2, 0x24AE0DC1, +"Beetle Adventure Racing! (J) [!]"}, +{0xEDF419A8, 0xBF1904CC, +"Beetle Adventure Racing! (U) [!]"}, +{0x08FFA4B7, 0x01F453B6, +"Big Mountain 2000 (U) [!]"}, +{0xAB7C101D, 0xEC58C8B0, +"Bio F.R.E.A.K.S. (E) [!]"}, +{0x08123595, 0x0510F1DE, +"Bio F.R.E.A.K.S. (U) [!]"}, +{0x7EAE2488, 0x9D40A35A, +"Bio Hazard 2 (J) [!]"}, +{0x7C64E6DB, 0x55B924DB, +"Blast Corps (E) [!]"}, +{0x7C647C25, 0xD9D901E6, +"Blast Corps (U) (V1.0) [!]"}, +{0x7C647E65, 0x1948D305, +"Blast Corps (U) (V1.1) [!]"}, +{0x65234451, 0xEBD3346F, +"Blast Dozer (J) [!]"}, +{0xD571C883, 0x822D3FCF, +"Blues Brothers 2000 (E) [!]"}, +{0x7CD08B12, 0x1153FF89, +"Blues Brothers 2000 (U) [!]"}, +{0x0B58B8CD, 0xB7B291D2, +"Body Harvest (E) [!]"}, +{0x5326696F, 0xFE9A99C3, +"Body Harvest (U) [!]"}, +{0xB3D451C6, 0xE1CB58E2, +"Bokujo Monogatari 2 (J) (V1.0) [!]"}, +{0x736657F6, 0x3C88A702, +"Bokujo Monogatari 2 (J) (V1.1)"}, +{0x7365D8F8, 0x9ED9326F, +"Bokujo Monogatari 2 (J) (V1.2)"}, +{0xDF6FF0F4, 0x29D14238, +"Bomberman 64 - Arcade Edition (J) [!]"}, +{0x237E73B4, 0xD63B6B37, +"Bomberman 64 - The Second Attack! (U) [!]"}, +{0x5A160336, 0xBC7B37B0, +"Bomberman 64 (E) [!]"}, +{0xF568D51E, 0x7E49BA1E, +"Bomberman 64 (U) [!]"}, +{0xD85C4E29, 0x88E276AF, +"Bomberman Hero (E) [!]"}, +{0x67FF12CC, 0x76BF0212, +"Bomberman Hero (J) [!]"}, +{0x4446FDD6, 0xE3788208, +"Bomberman Hero (U) [!]"}, +{0xD72FD14D, 0x1FED32C4, +"Bottom of the 9th (U) [!]"}, +{0x1E22CF2E, 0x42AAC813, +"Brunswick Circuit Pro Bowling (U) [!]"}, +{0xD5B2339C, 0xCABCCAED, +"Buck Bumble (E) [!]"}, +{0xD7C762B6, 0xF83D9642, +"Buck Bumble (J) [!]"}, +{0x85AE781A, 0xC756F05D, +"Buck Bumble (U) [!]"}, +{0xCEDCDE1E, 0x513A0502, +"Bust-A-Move 2 - Arcade Edition (E) [!]"}, +{0x8A86F073, 0xCD45E54B, +"Bust-A-Move 2 - Arcade Edition (U) [!]"}, +{0xE328B4FA, 0x004A28E1, +"Bust-A-Move 3 DX (E) [!]"}, +{0x4222D89F, 0xAFE0B637, +"Bust-A-Move '99 (U) [!]"}, +{0xAC16400E, 0xCF5D071A, +"California Speed (U) [!]"}, +{0x580162EC, 0xE3108BF1, +"Carmageddon 64 (G) [!]"}, +{0xE48E01F5, 0xE6E51F9B, +"Carmageddon 64 (E) [!]"}, +{0xF00F2D4E, 0x340FAAF4, +"Carmageddon 64 (U) [!]"}, +{0xA2C54BE7, 0x6719CBB2, +"Castlevania - Legacy of Darkness (E) [!]"}, +{0x1CC06338, 0x87388926, +"Castlevania - Legacy of Darkness (U) [!]"}, +{0x64F1B7CA, 0x71A23755, +"Castlevania (E) [!]"}, +{0xF35D5F95, 0x8AFE3D69, +"Castlevania (U) (V1.0) [!]"}, +{0x4BCDFF47, 0xAAA3AF8F, +"Castlevania (U) (V1.2) [!]"}, +{0xDCCF2134, 0x9DD63578, +"Centre Court Tennis (E) [!]"}, +{0xB9AF8CC6, 0xDEC9F19F, +"Chameleon Twist (E) [!]"}, +{0xA4F2F521, 0xF0EB168E, +"Chameleon Twist (J) [!]"}, +{0x6420535A, 0x50028062, +"Chameleon Twist (U) [!]"}, +{0x07A69D01, 0x9A7D41A1, +"Chameleon Twist 2 (E) [!]"}, +{0x0549765A, 0x93B9D042, +"Chameleon Twist 2 (J) [!]"}, +{0xCD538CE4, 0x618AFCF9, +"Chameleon Twist 2 (U) [!]"}, +{0xFB3C48D0, 0x8D28F69F, +"Charlie Blast's Territory (E) [!]"}, +{0x1E0E96E8, 0x4E28826B, +"Charlie Blast's Territory (U) [!]"}, +{0x2E359339, 0x3FA5EDA6, +"Chopper Attack (E) [!]"}, +{0x214CAD94, 0xBE1A3B24, +"Chopper Attack (U) [!]"}, +{0x2BCCF9C4, 0x403D9F6F, +"Choro Q 64 (J) [!]"}, +{0x26CD0F54, 0x53EBEFE0, +"Choro Q 64 II (J) [!]"}, +{0x8ACE6683, 0x3FBA426E, +"Chou Kuukan Night Pro Yakyuu King (J)"}, +{0x3A180FF4, 0x5C8E8AF7, +"Chou-Kuukan Night Pro Yakyuu King 2 (J)"}, +{0xA7941528, 0x61F1199D, +"Chou Snowbow Kids (J) [!]"}, +{0xF8009DB0, 0x6B291823, +"City-Tour GP-All Japan Grand Touring Car Championship (J) [!]"}, +{0xFA5A3DFF, 0xB4C9CDB9, +"Clay Fighter - Sculptor's Cut (U) [!]"}, +{0x2B6FA7C0, 0x09A71225, +"Clay Fighter 63 1-3 (U) (beta)"}, +{0x8E9692B3, 0x4264BB2A, +"Clay Fighter 63 1-3 (E) [!]"}, +{0xF03C24CA, 0xC5237BCC, +"Clay Fighter 63 1-3 (U) [!]"}, +{0xAE5B9465, 0xC54D6576, +"Command & Conquer (E) [!]"}, +{0xB5025BAD, 0xD32675FD, +"Command & Conquer (G) [!]"}, +{0x95286EB4, 0xB76AD58F, +"Command & Conquer (U) [!]"}, +{0x373F5889, 0x9A6CA80A, +"Conker's Bad Fur Day (E) [!]"}, +{0x30C7AC50, 0x7704072D, +"Conker's Bad Fur Day (U) [!]"}, +{0x46A3F7AF, 0x0F7591D0, +"Cruis'n Exotica (U) [!]"}, +{0x503EA760, 0xE1300E96, +"Cruis'n USA (E) [!]"}, +{0xFF2F2FB4, 0xD161149A, +"Cruis'n USA (U) (V1.0) [!]"}, +{0x5306CF45, 0xCBC49250, +"Cruis'n USA (U) (V1.1) [!]"}, +{0xB3402554, 0x7340C004, +"Cruis'n USA (U) (V1.2) [!]"}, +{0x83F3931E, 0xCB72223D, +"Cruis'n World (E) [!]"}, +{0xDFE61153, 0xD76118E6, +"Cruis'n World (U) [!]"}, +{0x83CB0B87, 0x7E325457, +"Custom Robo (J) [!]"}, +{0x079501B9, 0xAB0232AB, +"Custom Robo V2 (J) [!]"}, +{0xD1A78A07, 0x52A3DD3E, +"CyberTiger (E) [!]"}, +{0xE8FC8EA1, 0x9F738391, +"CyberTiger (U) [!]"}, +{0x7188F445, 0x84410A68, +"Dance Dance Revolution - Disney Dancing Museum (J) [!]"}, +{0x7ED67CD4, 0xB4415E6D, +"Dark Rift (E) [!]"}, +{0xA4A52B58, 0x23759841, +"Dark Rift (U) [!]"}, +{0xF5363349, 0xDBF9D21B, +"Deadly Arts (U) [!]"}, +{0x3F66A9D9, 0x9BCB5B00, +"Defi au Tetris Magique (Magical Tetris Challenge) (F) [!]"}, +{0x17C54A61, 0x4A83F2E7, +"Densha de GO! 64 (J) [!]"}, +{0xA5F667E1, 0xDA1FBD1F, +"Derby Stallion (J) [!]"}, +{0x630AA37D, 0x896BD7DB, +"Destruction Derby 64 (E) [!]"}, +{0xDEE584A2, 0x0F161187, +"Destruction Derby 64 (U) [!]"}, +{0x76712159, 0x35666812, +"Dexanoid R1 by Protest Design (PD) [!]"}, +{0x8979169C, 0xF189F6A0, +"Dezaemon 3D (J) [!]"}, +{0xFD73F775, 0x9724755A, +"Diddy Kong Racing (E) (V1.0) [!]"}, +{0x596E145B, 0xF7D9879F, +"Diddy Kong Racing (E) (V1.1) [!]"}, +{0xF389A35A, 0x17785562, +"Diddy Kong Racing (J) [!]"}, +{0x53D440E7, 0x7519B011, +"Diddy Kong Racing (U) (V1.0) [!]"}, +{0xE402430D, 0xD2FCFC9D, +"Diddy Kong Racing (U) (V1.1) [!]"}, +{0x906C3F77, 0xCE495EA1, +"Dinosaur Planet (U) (Beta) (Unreleased)"}, +{0xC16C421B, 0xA21580F7, +"Disney's Donald Duck - Goin' Quackers (U) [!]"}, +{0xD614E5BF, 0xA76DBCC1, +"Disney's Tarzan (E) [!]"}, +{0x001A3BD0, 0xAFB3DE1A, +"Disney's Tarzan (F) [!]"}, +{0x4C261323, 0x4F295E1A, +"Disney's Tarzan (G) [!]"}, +{0xCBFE69C7, 0xF2C0AB2A, +"Disney's Tarzan (U) [!]"}, +{0xBD8E206D, 0x98C35E1C, +"Dobutsu no Mori (J) [!]"}, +{0x3DF17480, 0x193DED5A, +"Donald Duck - Quack Attack (E) [!]"}, +{0x0DD4ABAB, 0xB5A2A91E, +"Donkey Kong 64 - Kiosk (U) [!]"}, +{0x11936D8C, 0x6F2C4B43, +"Donkey Kong 64 (E) [!]"}, +{0x053C89A7, 0xA5064302, +"Donkey Kong 64 (J) [!]"}, +{0xEC58EABF, 0xAD7C7169, +"Donkey Kong 64 (U) [!]"}, +{0x2C739EAC, 0x9EF77726, +"Doom 64 (E) [!]"}, +{0x7AA65B36, 0xFDCEE5AD, +"Doom 64 (J) [!]"}, +{0xA83E101A, 0xE937B69D, +"Doom 64 (U) (V1.0) [!]"}, +{0x423E96F4, 0xCE88F05B, +"Doom 64 (U) (v1.1)"}, +{0xBFF7B1C2, 0xAEBF148E, +"Doraemon - Mittsu no Seireiseki (J) [!]"}, +{0xB6306E99, 0xB63ED2B2, +"Doraemon 2 - Hikari no Shinden (J) [!]"}, +{0xA8275140, 0xB9B056E8, +"Doraemon 3 - Nobi Dai no Machi SOS! (J) [!]"}, +{0x769D4D13, 0xDA233FFE, +"Dr. Mario 64 (U) [!]"}, +{0xB6524461, 0xED6D04B1, +"Dual Heroes (E) [!]"}, +{0x056EAB63, 0xC215FCD5, +"Dual Heroes (J) [!]"}, +{0xA62230C3, 0xF0834488, +"Dual Heroes (U) [!]"}, +{0xFBB9F1FA, 0x6BF88689, +"Duck Dodgers Starring Daffy Duck (U) [!]"}, +{0xDC36626A, 0x3F3770CB, +"Duke Nukem - ZER0 H0UR (E) [!]"}, +{0x32CA974B, 0xB2C29C50, +"Duke Nukem - ZER0 H0UR (F) [!]"}, +{0x04DAF07F, 0x0D18E688, +"Duke Nukem - ZER0 H0UR (U) [!]"}, +{0x57BFF74D, 0xDE747743, +"Duke Nukem 64 (E) [!]"}, +{0x1E12883D, 0xD3B92718, +"Duke Nukem 64 (F)"}, +{0xA273AB56, 0xDA33DB9A, +"Duke Nukem 64 (U) [!]"}, +{0x492B9DE8, 0xC6CCC81C, +"Earthworm Jim 3D (E) [!]"}, +{0xDF574191, 0x9EB5123D, +"Earthworm Jim 3D (U) [!]"}, +{0x8C38E5DB, 0xB37C27D7, +"ECW Hardcore Revolution (E) [!]"}, +{0xBDF9766D, 0xBD068D70, +"ECW Hardcore Revolution (U) [!]"}, +{0xF2A653CB, 0x60633B3B, +"Elmo's Letter Adventure (U) [!]"}, +{0x02B1538F, 0xC94B88D0, +"Elmo's Number Journey (U) [!]"}, +{0xE13AE2DC, 0x4FB65CE8, +"Eltale Monsters (J) [!]"}, +{0xAF754F7B, 0x1DD17381, +"Excitebike 64 - Kiosk (U) [!]"}, +{0x202A8EE4, 0x83F88B89, +"Excitebike 64 (E) [!]"}, +{0x861C3519, 0xF6091CE5, +"Excitebike 64 (J) [!]"}, +{0x07861842, 0xA12EBC9F, +"Excitebike 64 (U) [!]"}, +{0x8E9D834E, 0x1E8B29A9, +"Extreme-G (E) [!]"}, +{0xEE802DC4, 0x690BD57D, +"Extreme-G (J) [!]"}, +{0xFDA245D2, 0xA74A3D47, +"Extreme-G (U) [!]"}, +{0x1185EC85, 0x4B5A7731, +"Extreme-G XG2 (E) [!]"}, +{0x399B9B81, 0xD533AD11, +"Extreme-G XG2 (J) [!]"}, +{0x5CD4150B, 0x470CC2F1, +"Extreme-G XG2 (U) [!]"}, +{0xFDD248B2, 0x569A020E, +"F-1 Pole Position 64 (E) [!]"}, +{0xAE82687A, 0x9A3F388D, +"F-1 Pole Position 64 (U) [!]"}, +{0xCC3CC8B3, 0x0EC405A4, +"F-1 World Grand Prix (E) [!]"}, +{0xB70BAEE5, 0x3A5005A8, +"F-1 World Grand Prix (F) [!]"}, +{0x38442634, 0x66B3F060, +"F-1 World Grand Prix (G)"}, +{0x64BF47C4, 0xF4BD22BA, +"F-1 World Grand Prix (J) [!]"}, +{0xCC3CC8B3, 0x0EC405A4, +"F-1 World Grand Prix (U) [!]"}, +{0x07C1866E, 0x5775CCDE, +"F-1 World Grand Prix II (E) [!]"}, +{0x6DFF4C37, 0xB1B763FD, +"Famista 64 (J) [!]"}, +{0x3CECBCB8, 0x6126BF07, +"F1 Racing Championship (E) [!]"}, +{0x0E31EDF0, 0xC37249D5, +"FIFA - Road to World Cup 98 (E) [!]"}, +{0xF5733C67, 0x17A3973A, +"FIFA - Road to World Cup 98 (J) [!]"}, +{0xCB1ACDDE, 0xCF291DF2, +"FIFA - Road to World Cup 98 (U) [!]"}, +{0x0198A651, 0xFC219D84, +"FIFA 99 (E) [!]"}, +{0x7613A630, 0x3ED696F3, +"FIFA 99 (U) [!]"}, +{0xC3F19159, 0x65D2BC5A, +"FIFA Soccer 64 (E) [!]"}, +{0xC3F19159, 0x65D2BC5A, +"FIFA Soccer 64 (U) [!]"}, +{0x36F1C74B, 0xF2029939, +"Fighter's Destiny (E) [!]"}, +{0x0C41F9C2, 0x01717A0D, +"Fighter's Destiny (F) [!]"}, +{0xFE94E570, 0xE4873A9C, +"Fighter's Destiny (G) [!]"}, +{0x52F78805, 0x8B8FCAB7, +"Fighter's Destiny (U) [!]"}, +{0xAEEF2F45, 0xF97E30F1, +"Fighter's Destiny 2 (U) [!]"}, +{0x49E46C2D, 0x7B1A110C, +"Fighting Cup (J) [!]"}, +{0x66CF0FFE, 0xAD697F9C, +"Fighting Force 64 (E) [!]"}, +{0x32EFC7CB, 0xC3EA3F20, +"Fighting Force 64 (U) [!]"}, +{0x28D5562D, 0xE4D5AE50, +"Fire Electric Pen (J) [!]"}, +{0x22E9623F, 0xB60E52AD, +"Flying Dragon (E) [!]"}, +{0xA92D52E5, 0x1D26B655, +"Flying Dragon (U) [!]"}, +{0x142A17AA, 0x13028D96, +"Forsaken 64 (E) [!]"}, +{0xC3CD76FF, 0x9B9DCBDE, +"Forsaken 64 (G) [!]"}, +{0x9E330C01, 0x8C0314BA, +"Forsaken 64 (U) [!]"}, +{0x3261D479, 0xED0DBC25, +"Fox Sports College Hoops '99 (U) [!]"}, +{0xE8E5B179, 0x44AA30E8, +"Frogger 2 (U) (Unreleased Alpha)"}, +{0xF774EAEE, 0xF0D8B13E, +"Fushigi no Dungeon - Furai no Shiren 2 (J) [!]"}, +{0x776646F6, 0x06B9AC2B, +"F-Zero X (E) [!]"}, +{0x4D3E622E, 0x9B828B4E, +"F-Zero X (J) [!]"}, +{0xB30ED978, 0x3003C9F9, +"F-Zero X (U) [!]"}, +{0x68FCF726, 0x49658CBC, +"G.A.S.P! Fighter's NEXTream (E) [!]"}, +{0xAF8679B6, 0x5E1011BF, +"G.A.S.P! Fighter's NEXTream (J) [!]"}, +{0x8F89ABA0, 0xC34C2610, +"GameShark V3.3 (Unl)"}, +{0x832C168B, 0x56A2CDAE, +"Ganbare Goemon (J)"}, +{0x457B9CD9, 0x09C55352, +"Ganbare Goemon 2 - Deorudero Douchuu Obake Tenkomori (J) [!]"}, +{0xB2C6D27F, 0x2DA48CFD, +"Ganbare Goemon - Mononoke Sugoroku (J)"}, +{0x21FFFD0A, 0xFA0D1D98, +"Ganbare Nippon Olympics 2000 (J) [!]"}, +{0xD543BCD6, 0x2BA5E256, +"Gauntlet Legends (E) [!]"}, +{0x70B0260E, 0x6716D04C, +"Gauntlet Legends (J) [!]"}, +{0x729B5E32, 0xB728D980, +"Gauntlet Legends (U) [!]"}, +{0x489C84E6, 0x4C6E49F9, +"Getter Love!! Cho Renai Party Game (J) [!]"}, +{0x99179359, 0x2FE7EBC3, +"Gex 3 - Deep Cover Gecko (E) [!]"}, +{0x874733A4, 0xA823745A, +"Gex 3 - Deep Cover Gecko (FG) [!]"}, +{0x3EDC7E12, 0xE26C1CC9, +"Gex 3 - Deep Cover Gecko (U) [!]"}, +{0xE68A000E, 0x639166DD, +"Gex 64 - Enter the Gecko (E) [!]"}, +{0x89FED774, 0xCAAFE21B, +"Gex 64 - Enter the Gecko (U) [!]"}, +{0xF5237301, 0x99E3EE93, +"Glover (E) [!]"}, +{0x8E6E01FF, 0xCCB4F948, +"Glover (U) [!]"}, +{0x4252A5AD, 0xAE6FBF4E, +"Goemon's Great Adventure (U) [!]"}, +{0x4690FB1C, 0x4CD56D44, +"Golden Nugget 64 (U) [!]"}, +{0x0414CA61, 0x2E57B8AA, +"GoldenEye 007 (E) [!]"}, +{0xA24F4CF1, 0xA82327BA, +"GoldenEye 007 (J) [!]"}, +{0xDCBC50D1, 0x09FD1AA3, +"GoldenEye 007 (U) [!]"}, +{0xEE4A0E33, 0x8FD588C9, +"GT 64 Championship Edition (E) [!]"}, +{0xC49ADCA2, 0xF1501B62, +"GT 64 Championship Edition (U) [!]"}, +{0x95A80114, 0xE0B72A7F, +"Hamster Monogatari 64 (J)"}, +{0x36F22FBF, 0x318912F2, +"Hanafuda 64 - Tenshi no Yakusoku (J) [!]"}, +{0x09AE57B1, 0x182A5637, +"Harukanaru Augusta Masters 98 (J) [!]"}, +{0x98DF9DFC, 0x6606C189, +"Harvest Moon 64 (U) [!]"}, +{0x3E70E866, 0x4438BAE8, +"Heiwa Pachinko World (J) [!]"}, +{0xAE90DBEB, 0x79B89123, +"Hercules - The Legendary Journeys (E) [!]"}, +{0x7F3CEB77, 0x8981030A, +"Hercules - The Legendary Journeys (U) [!]"}, +{0x95B2B30B, 0x2B6415C1, +"Hexen (E) [!]"}, +{0x5C1B5FBD, 0x7E961634, +"Hexen (F)"}, +{0x9AB3B50A, 0xBC666105, +"Hexen (G) [!]"}, +{0x66751A57, 0x54A29D6E, +"Hexen (J) [!]"}, +{0x9CAB6AEA, 0x87C61C00, +"Hexen (U) [!]"}, +{0xD3F10E5D, 0x052EA579, +"Hey You, Pikachu! (U) [!]"}, +{0x35FF8F1A, 0x6E79E3BE, +"Hiro no Ken Twin (J) [!]"}, +{0x277B129D, 0xDD3879FF, +"Holy Magic Century (E) [!]"}, +{0xB35FEBB0, 0x7427B204, +"Holy Magic Century (F)"}, +{0x75FA0E14, 0xC9B3D105, +"Holy Magic Century (G) [!]"}, +{0xC1D702BD, 0x6D416547, +"Hoshi no Kirby 64 (J) (v1.0)"}, +{0xCA1BB86F, 0x41CCA5C5, +"Hoshi no Kirby 64 (J) (V1.1)"}, +{0x0C581C7A, 0x3D6E20E4, +"Hoshi no Kirby 64 (J) (v1.2)"}, +{0xBCB1F89F, 0x060752A2, +"Hoshi no Kirby 64 (J) (v1.3)"}, +{0xE7D20193, 0xC1158E93, +"Hot Wheels Turbo Racing (E) [!]"}, +{0xC7C98F8E, 0x42145DDE, +"Hot Wheels Turbo Racing (U) [!]"}, +{0x72611D7D, 0x9919BDD2, +"HSV Adventure Racing (A)"}, +{0x5535972E, 0xBD8E3295, +"Human Grand Prix (J) [!]"}, +{0x641D3A7F, 0x86820466, +"Hybrid Heaven (E) [!]"}, +{0x0DE2CE36, 0xD41D29E6, +"Hybrid Heaven (J) [!]"}, +{0x102888BF, 0x434888CA, +"Hybrid Heaven (U) [!]"}, +{0xB58988E9, 0xB1FC4BE8, +"Hydro Thunder (E) [!]"}, +{0x29A045CE, 0xABA9060E, +"Hydro Thunder (F)"}, +{0xC8DC65EB, 0x3D8C8904, +"Hydro Thunder (U) [!]"}, +{0x69458B9E, 0xFC95F936, +"Iggy-kun no Bura Bura Poyon (J) [!]"}, +{0xD692CC5E, 0xEC58D072, +"Iggy's Reckin' Balls (E) [!]"}, +{0xE616B5BC, 0xC9658B88, +"Iggy's Reckin' Balls (U) [!]"}, +{0xAF9DCC15, 0x1A723D88, +"Indiana Jones and the Infernal Machine (U) [!]"}, +{0xE436467A, 0x82DE8F9B, +"Indy Racing 2000 (U) [!]"}, +{0x8C138BE0, 0x95700E46, +"In-Fisherman Bass Hunter 64 (U) [!]"}, +{0x336364A0, 0x06C8D5BF, +"International Superstar Soccer 2000 (E) [!]"}, +{0xBAE8E871, 0x35FF944E, +"International Superstar Soccer 2000 (FI)"}, +{0x8E835437, 0xCD5748B4, +"International Superstar Soccer 2000 (U) [!]"}, +{0xE2D37CF0, 0xF57E4EAE, +"International Superstar Soccer 64 (E) [!]"}, +{0x5F2763C4, 0x62412AE5, +"International Superstar Soccer 64 (U) [!]"}, +{0xF41B6343, 0xC10661E6, +"International Superstar Soccer '98 (E) [!]"}, +{0x7F0FDA09, 0x6061CE0B, +"International Superstar Soccer '98 (U) [!]"}, +{0x20073BC7, 0x5E3B0111, +"International Track and Field 2000 (U) [!]"}, +{0x6712C779, 0x3B72781D, +"International Track and Field Summer Games (E) [!]"}, +{0x87766747, 0x91C27165, +"J. League Dynamite Soccer (J) [!]"}, +{0x4FBFA429, 0x6920BB15, +"J. League Eleven Beat 1997 (J) [!]"}, +{0x54554A42, 0xE4985FFB, +"J. League Live 64 (J)"}, +{0xE8D29DA0, 0x15E61D94, +"J. League Tactics Soccer (J) [!]"}, +{0xC73AD016, 0x48C5537D, +"Jangou Simulation Mahjong Do 64 (J) [!]"}, +{0x69256460, 0xB9A3F586, +"Jeopardy! (U) [!]"}, +{0x21F7ABFB, 0x6A8AA7E8, +"Jeremy McGrath Supercross 2000 (E) [!]"}, +{0xBB30B1A5, 0xFCF712CE, +"Jeremy McGrath Supercross 2000 (U) [!]"}, +{0xDFD8AB47, 0x3CDBEB89, +"Jet Force Gemini - Kiosk (U) [!]"}, +{0x68D7A1DE, 0x0079834A, +"Jet Force Gemini (E) [!]"}, +{0x8A6009B6, 0x94ACE150, +"Jet Force Gemini (U) [!]"}, +{0xCDB8B4D0, 0x8832352D, +"Jet Force Gemini (U) [f1]"}, +{0xAF19D9F5, 0xB70223CC, +"Jikkyou G1 Stable (J) [!]"}, +{0x63112A53, 0xA29FA88F, +"Jikkyou J. League 1999 - Perfect Striker 2 (J) [!]"}, +{0x146C4366, 0x72A6DEB3, +"Jikkyou J. League Perfect Striker (J) [!]"}, +{0x0AC244D1, 0x1F0EC605, +"Jikkyou Powerful Pro Yakyuu 2000 (J) (V1.0) [!]"}, +{0x4264DF23, 0xBE28BDF7, +"Jikkyou Powerful Pro Yakyuu 2000 (J) (V1.1) [!]"}, +{0x6EDD4766, 0xA93E9BA8, +"Jikkyou Powerful Pro Baseball Basic 2001 (J) [!]"}, +{0x3FEA5620, 0x7456DB40, +"Jikkyou World Cup France '98 (J) (v1.0)"}, +{0xC954B38C, 0x6F62BEB3, +"Jikkyou World Cup France '98 (J) (v1.1)"}, +{0xE1C7ABD6, 0x4E707F28, +"Jikkyou World Cup France '98 (J) (v1.2)"}, +{0xE0A79F8C, 0x32CC97FA, +"Jikkyou World Soccer 3 (J) [!]"}, +{0x4AAAF6ED, 0x376428AD, +"Jinsei Game 64 (J) [!]"}, +{0x0F743195, 0xD8A6DB95, +"John Romero's Daikatana (E) [!]"}, +{0x9D7E3C4B, 0xE60F4A6C, +"John Romero's Daikatana (J) [!]"}, +{0xD0151AB0, 0xFE5CA14B, +"John Romero's Daikatana (U) [!]"}, +{0x4F29474F, 0x30CB707A, +"Kakutou Denshou - F-Cup Maniax (J) [!]"}, +{0x36281F23, 0x009756CF, +"Ken Griffey Jr.'s Slugfest (U) [!]"}, +{0x979B263E, 0xF8470004, +"Killer Instinct Gold (E) [!]"}, +{0x9E8FE2BA, 0x8B270770, +"Killer Instinct Gold (U) (V1.0) [!]"}, +{0x9E8FCDFA, 0x49F5652B, +"Killer Instinct Gold (U) (V1.1) [!]"}, +{0xF908CA4C, 0x36464327, +"Killer Instinct Gold (U) (V1.2) [!]"}, +{0x519EA4E1, 0xEB7584E8, +"King Hill 64 - Extreme Snowboarding (J) [!]"}, +{0x75BC6AD6, 0x78552BC9, +"Kiratto Kaiketsu! 64 Tanteidan (J) [!]"}, +{0x0D93BA11, 0x683868A6, +"Kirby 64 - The Crystal Shards (E) [!]"}, +{0x46039FB4, 0x0337822C, +"Kirby 64 - The Crystal Shards (U) [!]"}, +{0x4A997C74, 0xE2087F99, +"Knife Edge - Nose Gunner (E) [!]"}, +{0x931AEF3F, 0xEF196B90, +"Knife Edge - Nose Gunner (J) [!]"}, +{0xFCE0D799, 0x65316C54, +"Knife Edge - Nose Gunner (U) [!]"}, +{0xE3D6A795, 0x2A1C5D3C, +"Knockout Kings 2000 (E) [!]"}, +{0x0894909C, 0xDAD4D82D, +"Knockout Kings 2000 (U) [!]"}, +{0x1739EFBA, 0xD0B43A68, +"Kobe Bryant's NBA Courtside (E) [!]"}, +{0x616B8494, 0x8A509210, +"Kobe Bryant's NBA Courtside (U) [!]"}, +{0x5E3E60E8, 0x4AB5D495, +"Kuiki Uhabi Suigo (J) [!]"}, +{0x7F304099, 0x52CF5276, +"Last Legion UX (J) [!]"}, +{0xE97955C6, 0xBC338D38, +"Legend of Zelda 2, The - Majora's Mask (E) [!]"}, +{0x0A5D8F83, 0x98C5371A, +"Legend of Zelda, The - Majora's Mask (E) (M4) (v1.1)"}, +{0x5354631C, 0x03A2DEF0, +"Legend of Zelda 2, The - Majora's Mask (U) [!]"}, +{0xB044B569, 0x373C1985, +"Legend of Zelda, The - Ocarina of Time (E) (V1.0) [!]"}, +{0xB2055FBD, 0x0BAB4E0C, +"Legend of Zelda, The - Ocarina of Time (E) (M3) (V1.1)"}, +{0x09465AC3, 0xF8CB501B, +"Legend of Zelda, The - Ocarina of Time (E) (GC Version)"}, +{0xEC7011B7, 0x7616D72B, +"Legend of Zelda, The - Ocarina of Time (U) (V1.0) [!]"}, +{0xD43DA81F, 0x021E1E19, +"Legend of Zelda, The - Ocarina of Time (U) (V1.1) [!]"}, +{0x693BA2AE, 0xB7F14E9F, +"Legend of Zelda, The - Ocarina of Time (U) (V1.2) [!]"}, +{0xF034001A, 0xAE47ED06, +"Legend of Zelda, The - Ocarina of Time - Master Quest (U) (GC Version)"}, +{0xF3DD35BA, 0x4152E075, +"Legend of Zelda, The - Ocarina of Time (U) (GC Version)"}, +{0x1D4136F3, 0xAF63EEA9, +"Legend of Zelda, The - Ocarina of Time - Master Quest (E) [h1C]"}, +{0x1D4136F3, 0xAF63EEA9, +"Legend of Zelda, The - Ocarina of Time - Master Quest (E)"}, +{0x27A3831D, 0xB505A533, +"Legend of Zelda, The - Ocarina of Time - Master Quest (E) [f1] (NTSC)"}, +{0xB443EB08, 0x4DB31193, +"Legend of Zelda, The - Majora's Mask - Collector's Edition (U) (GC Version)"}, +{0xB443EB08, 0x4DB31193, +"Legend of Zelda, The - Majora's Mask (U) (GC Version)"}, +{0x917D18F6, 0x69BC5453, +"Legend of Zelda, The - Ocarina of Time - Master Quest (U) (Debug Rom)"}, +{0x6AECEC4F, 0xF0924814, +"Legend of Zelda, The - Majora's Mask - Collector's Edition (E) (GC Version)"}, +{0xBF799345, 0x39FF7A02, +"Legend of Zelda, The - Majora's Mask (U) (Demo)"}, +{0xF478D8B3, 0x9716DD6D, +"LEGO Racers (E) [!]"}, +{0x096A40EA, 0x8ABE0A10, +"LEGO Racers (U) [!]"}, +{0x2B696CB4, 0x7B93DCD8, +"Les Razmoket - La Chasse Aux Tresors (F) [!]"}, +{0x3D67C62B, 0x31D03150, +"Let's Smash Tennis (J) [!]"}, +{0x60460680, 0x305F0E72, +"Lode Runner 3-D (E) [!]"}, +{0x964ADD0B, 0xB29213DB, +"Lode Runner 3-D (J) [!]"}, +{0x255018DF, 0x57D6AE3A, +"Lode Runner 3-D (U) [!]"}, +{0x0AA0055B, 0x7637DF65, +"Looney Tunes - Duck Dodgers (E) [!]"}, +{0x2483F22B, 0x136E025E, +"Lylat Wars (A) [!]"}, +{0xF4CBE92C, 0xB392ED12, +"Lylat Wars (E) [!]"}, +{0x1145443D, 0x11610EDB, +"Mace - The Dark Age (E) [!]"}, +{0x6B700750, 0x29D621FE, +"Mace - The Dark Age (U) [!]"}, +{0x0CB81686, 0x5FD85A81, +"Madden 2000 (U) [!]"}, +{0xA197CB52, 0x7520DE0E, +"Madden Football 64 (E) [!]"}, +{0x13836389, 0x265B3C76, +"Madden Football 64 (U) [!]"}, +{0xEB38F792, 0x190EA246, +"Madden NFL 2001 (U) [!]"}, +{0xD7134F8D, 0xC11A00B5, +"Madden NFL 2002 (U) [!]"}, +{0x3925D625, 0x8C83C75E, +"Madden NFL 99 (E) [!]"}, +{0xDEB78BBA, 0x52F6BD9D, +"Madden NFL 99 (U) [!]"}, +{0xE4906679, 0x9F243F05, +"Magical Tetris Challenge (E) [!]"}, +{0xE1EF93F7, 0x14908B0B, +"Magical Tetris Challenge (G) [!]"}, +{0x80C8564A, 0x929C65AB, +"Magical Tetris Challenge (J) [!]"}, +{0x75B61647, 0x7ADABF78, +"Magical Tetris Challenge (U) [!]"}, +{0xC53EDC41, 0xECE19359, +"Mahjong 64 (KOEI) (J) [!]"}, +{0xCCCC821E, 0x96E88A83, +"Mahjong Hourouki Classic (J) [!]"}, +{0x0FC42C70, 0x8754F1CD, +"Mahjong Master (J) [!]"}, +{0xCDB998BE, 0x1024A5C8, +"Major League Baseball Featuring Ken Griffey Jr. (E) [!]"}, +{0x80C1C05C, 0xEA065EF4, +"Major League Baseball Featuring Ken Griffey Jr. (U) [!]"}, +{0x9CCE5B1D, 0x6351E283, +"MAME 64 Emulator V1.0 (PD)"}, +{0x62E957D0, 0x7FC15A5D, +"Mario Golf (E) [!]"}, +{0x664BA3D4, 0x678A80B7, +"Mario Golf (U) [!]"}, +{0xD48944D1, 0xB0D93A0E, +"Mario Golf 64 (J) [!]"}, +{0xC3B6DE9D, 0x65D2DE76, +"Mario Kart 64 (E) (V1.0) [!]"}, +{0x2577C7D4, 0xD18FAAAE, +"Mario Kart 64 (E) (V1.1) [!]"}, +{0x6BFF4758, 0xE5FF5D5E, +"Mario Kart 64 (J) (V1.0) [!]"}, +{0xC9C3A987, 0x5810344C, +"Mario Kart 64 (J) (V1.1) [!]"}, +{0x3E5055B6, 0x2E92DA52, +"Mario Kart 64 (U) [!]"}, +{0x9A9890AC, 0xF0C313DF, +"Mario no Photopie (J) [!]"}, +{0x9C663069, 0x80F24A80, +"Mario Party (E) [!]"}, +{0xADA815BE, 0x6028622F, +"Mario Party (J) [!]"}, +{0x2829657E, 0xA0621877, +"Mario Party (U) [!]"}, +{0x82380387, 0xDFC744D9, +"Mario Party 2 (E) [!]"}, +{0xED567D0F, 0x38B08915, +"Mario Party 2 (J) [!]"}, +{0x9EA95858, 0xAF72B618, +"Mario Party 2 (U) [!]"}, +{0xC5674160, 0x0F5F453C, +"Mario Party 3 (E) [!]"}, +{0x0B0AB4CD, 0x7B158937, +"Mario Party 3 (J) [!]"}, +{0x7C3829D9, 0x6E8247CE, +"Mario Party 3 (U) [!]"}, +{0x3BA7CDDC, 0x464E52A0, +"Mario Story (J) [!]"}, +{0x839F3AD5, 0x406D15FA, +"Mario Tennis (E) [!]"}, +{0x3A6C42B5, 0x1ACADA1B, +"Mario Tennis (J) [!]"}, +{0x5001CF4F, 0xF30CB3BD, +"Mario Tennis (U) [!]"}, +{0x0EC158F5, 0xFB3E6896, +"Mega Man 64 (U) [!]"}, +{0x1001F10C, 0x3D51D8C1, +"Mia Hamm Soccer 64 (U) [!]"}, +{0xE36166C2, 0x8613A2E5, +"Michael Owens WLS 2000 (E) [!]"}, +{0x736AE6AF, 0x4117E9C7, +"Mickey no Racing Challenge USA (J) [!]"}, +{0xDED0DD9A, 0xE78225A7, +"Mickey's Speedway USA (E) [!]"}, +{0xFA8C4571, 0xBBE7F9C0, +"Mickey's Speedway USA (U) [!]"}, +{0x2A49018D, 0xD0034A02, +"Micro Machines 64 Turbo (E) [!]"}, +{0xF1850C35, 0xACE07912, +"Micro Machines 64 Turbo (U) [!]"}, +{0xE4B35E4C, 0x1AC45CC9, +"Midway's Greatest Arcade Hits Volume 1 (U) [!]"}, +{0x09D53E16, 0x3AB268B9, +"Mike Piazza's Strike Zone (U) [!]"}, +{0x9A490D9D, 0x8F013ADC, +"Milo's Astro Lanes (E) [!]"}, +{0x2E955ECD, 0xF3000884, +"Milo's Astro Lanes (U) [!]"}, +{0x418BDA98, 0x248A0F58, +"Mischief Makers (E) [!]"}, +{0x0B93051B, 0x603D81F9, +"Mischief Makers (U) [!]"}, +{0x2256ECDA, 0x71AB1B9C, +"Mission Impossible (E) [!]"}, +{0x20095B34, 0x343D9E87, +"Mission Impossible (F) [!]"}, +{0x93EB3F7E, 0x81675E44, +"Mission Impossible (G) [!]"}, +{0xEBA949DC, 0x39BAECBD, +"Mission Impossible (I) [!]"}, +{0x5F6A04E2, 0xD4FA070D, +"Mission Impossible (S) [!]"}, +{0x26035CF8, 0x802B9135, +"Mission Impossible (U) [!]"}, +{0x28768D6D, 0xB379976C, +"Monaco Grand Prix (U) [!]"}, +{0x5AC383E1, 0xD712E387, +"Monopoly (U) [!]"}, +{0xD3D806FC, 0xB43AA2A8, +"Monster Truck Madness 64 (E) [!]"}, +{0xB19AD999, 0x7E585118, +"Monster Truck Madness 64 (U) [!]"}, +{0xE8E8DD70, 0x415DD198, +"Morita Shogi 64 (J) [!]"}, +{0x73036F3B, 0xCE0D69E9, +"Mortal Kombat 4 (E) [!]"}, +{0x417DD4F4, 0x1B482FE2, +"Mortal Kombat 4 (U) [!]"}, +{0xFF44EDC4, 0x1AAE9213, +"Mortal Kombat Mythologies - Sub-Zero (E) [!]"}, +{0xC34304AC, 0x2D79C021, +"Mortal Kombat Mythologies - Sub-Zero (U) [!]"}, +{0x8C3D1192, 0xBEF172E1, +"Mortal Kombat Trilogy (E) [!]"}, +{0xD9F75C12, 0xA8859B59, +"Mortal Kombat Trilogy (U) (V1.0) [!]"}, +{0x83F33AA9, 0xA901D40D, +"Mortal Kombat Trilogy (U) (V1.2) [!]"}, +{0xB8F0BD03, 0x4479189E, +"MRC - Multi Racing Championship (E) [!]"}, +{0xA6B6B413, 0x15D113CC, +"MRC - Multi Racing Championship (J) [!]"}, +{0x2AF9B65C, 0x85E2A2D7, +"MRC - Multi Racing Championship (U) [!]"}, +{0x1938525C, 0x586E9656, +"Ms. Pac-Man Maze Madness (U) [!]"}, +{0xF5360FBE, 0x2BF1691D, +"Mystical Ninja - Starring Goemon (E) [!]"}, +{0xFCBCCB21, 0x72903C6B, +"Mystical Ninja - Starring Goemon (U) [!]"}, +{0x7F9345D3, 0x841ECADE, +"Mystical Ninja 2 - Starring Goemon (E) [!]"}, +{0xAE2D3A35, 0x24F0D41A, +"Nagano Olympic Hockey '98 (E) [!]"}, +{0x7EC22587, 0xEF1AE323, +"Nagano Olympic Hockey '98 (U) [!]"}, +{0x90F43037, 0x5C5370F5, +"Nagano Olympic Hockey '98 (J) [!]"}, +{0x6D452016, 0x713C09EE, +"Nagano Winter Olympics '98 (E) [!]"}, +{0x2FC5C34C, 0x7A05CC9D, +"Nagano Winter Olympics '98 (J) [!]"}, +{0x8D2BAE98, 0xD73725BF, +"Nagano Winter Olympics '98 (U) [!]"}, +{0x5129B6DA, 0x9DEF3C8C, +"Namco Museum 64 (U) [!]"}, +{0xDF331A18, 0x5FD4E044, +"NASCAR 2000 (U) [!]"}, +{0xAE4992C9, 0x9253B253, +"NASCAR 99 (E) [!]"}, +{0x23749578, 0x80DC58FD, +"NASCAR 99 (U) [!]"}, +{0x916852D8, 0x73DBEAEF, +"NBA Courtside 2 - Featuring Kobe Bryant (U) [!]"}, +{0xC788DCAE, 0xBD03000A, +"NBA Hangtime (E) [!]"}, +{0x4E69B487, 0xFE18E290, +"NBA Hangtime (U) [!]"}, +{0xAAE11F01, 0x2625A045, +"NBA In the Zone 2 (J) [!]"}, +{0xB3054F9F, 0x96B69EB5, +"NBA In the Zone 2000 (E) [!]"}, +{0x8DF95B18, 0xECDA497B, +"NBA In the Zone 2000 (U) [!]"}, +{0x36ACBA9B, 0xF28D4D94, +"NBA In the Zone '98 (J) [!]"}, +{0x6A121930, 0x665CC274, +"NBA In the Zone '98 (U) [!]"}, +{0xA292524F, 0x3D6C2A49, +"NBA In the Zone '99 (U) [!]"}, +{0xB6D0CAA0, 0xE3F493C8, +"NBA Jam 2000 (E) [!]"}, +{0xEBEEA8DB, 0xF2ECB23C, +"NBA Jam 2000 (U) [!]"}, +{0xE600831E, 0x59F422A8, +"NBA Jam 99 (E) [!]"}, +{0x810729F6, 0xE03FCFC1, +"NBA Jam 99 (U) [!]"}, +{0xEB499C8F, 0xCD4567B6, +"NBA Live 2000 (E) [!]"}, +{0x5F25B0EE, 0x6227C1DB, +"NBA Live 2000 (U) [!]"}, +{0xCF84F45F, 0x00E4F6EB, +"NBA Live 99 (E) [!]"}, +{0x57F81C9B, 0x1133FA35, +"NBA Live 99 (U) [!]"}, +{0xACDE962F, 0xB2CBF87F, +"NBA Pro 98 (E) [!]"}, +{0x8D1780B6, 0x57B3B976, +"NBA Pro 99 (E) [!]"}, +{0x3FFE80F4, 0xA7C15F7E, +"NBA Showtime - NBA on NBC (U) [!]"}, +{0x147E0EDB, 0x36C5B12C, +"Neon Genesis Evangelion (J) [!]"}, +{0xE61CFF0A, 0xCE1C0D71, +"New Tetris, The (E) [!]"}, +{0x2153143F, 0x992D6351, +"New Tetris, The (U) [!]"}, +{0x30EAD54F, 0x31620BF6, +"NFL Blitz - Special Edition (U) [!]"}, +{0xD094B170, 0xD7C4B5CC, +"NFL Blitz (U) [!]"}, +{0x15A00969, 0x34E5A285, +"NFL Blitz 2000 (U) [!]"}, +{0x36FA35EB, 0xE85E2E36, +"NFL Blitz 2001 (U) [!]"}, +{0x88BD5A9E, 0xE81FDFBF, +"NFL Quarterback Club 2000 (E) [!]"}, +{0xE3AB4ED0, 0x83040DD2, +"NFL Quarterback Club 2000 (U) [!]"}, +{0x28784622, 0xFFB22985, +"NFL Quarterback Club 2001 (U) [!]"}, +{0x4B629EF4, 0x99B21D9B, +"NFL Quarterback Club 98 (E) [!]"}, +{0xD89BE2F8, 0x99C97ADF, +"NFL Quarterback Club 98 (U) [!]"}, +{0x52A3CF47, 0x4EC13BFC, +"NFL Quarterback Club 99 (E) [!]"}, +{0xBE76EDFF, 0x20452D09, +"NFL Quarterback Club 99 (U) [!]"}, +{0x287D601E, 0xABF4F8AE, +"NHL 99 (E) [!]"}, +{0x591A806E, 0xA5E6921D, +"NHL 99 (U) [!]"}, +{0x82EFDC30, 0x806A2461, +"NHL Blades of Steel '99 (U) [!]"}, +{0x29CE7692, 0x71C58579, +"NHL Breakaway 98 (E) [!]"}, +{0x6DFDCDC3, 0x4DE701C8, +"NHL Breakaway 98 (U) [!]"}, +{0x874621CB, 0x0031C127, +"NHL Breakaway 99 (E) [!]"}, +{0x441768D0, 0x7D73F24F, +"NHL Breakaway 99 (U) [!]"}, +{0xA9895CD9, 0x7020016C, +"NHL Pro 99 (E) [!]"}, +{0x2857674D, 0xCC4337DA, +"Nightmare Creatures (U) [!]"}, +{0xCD3C3CDF, 0x317793FA, +"Nintama Rantarou 64 (J)"}, +{0x8A97A197, 0x272DF6C1, +"Nuclear Strike 64 (E) [!]"}, +{0x8F50B845, 0xD729D22F, +"Nuclear Strike 64 (G) [!]"}, +{0x4998DDBB, 0xF7B7AEBC, +"Nuclear Strike 64 (U) [!]"}, +{0x5B9B1618, 0x1B43C649, +"Nushi Tsuri 64 - Shiokaze ni Notte (J) [!]"}, +{0xD83BB920, 0xCC406416, +"Nushi Tsuri 64 (J) [!]"}, +{0xE86415A6, 0x98395B53, +"O.D.T (Or Die Trying) (E) (M5) (Unreleased Final)"}, +{0x2655BB70, 0x667D9925, +"O.D.T (Or Die Trying) (U) (M3) (Unreleased Final)"}, +{0x812289D0, 0xC2E53296, +"Off Road Challenge (E) [!]"}, +{0x319093EC, 0x0FC209EF, +"Off Road Challenge (U) [!]"}, +{0x0375CF67, 0x56A93FAA, +"Ogre Battle 64 - Person of Lordly Caliber (J) (V1.1) [!]"}, +{0xE6419BC5, 0x69011DE3, +"Ogre Battle 64 - Person of Lordly Caliber (U) [!]"}, +{0xDC649466, 0x572FF0D9, +"Onegai Monsters (J) [!]"}, +{0x74554B3B, 0xF4AEBCB5, +"Pachinko 365 Nichi (J) [!]"}, +{0x19AB29AF, 0xC71BCD28, +"Paper Mario (E) [!]"}, +{0x65EEE53A, 0xED7D733C, +"Paper Mario (U) [!]"}, +{0xAC976B38, 0xC3A9C97A, +"Paperboy (E) [!]"}, +{0x3E198D9E, 0xF2E1267E, +"Paperboy (U) [!]"}, +{0xCFE2CB31, 0x4D6B1E1D, +"Parlor! Pro 64 Pachinko Jikki Simulation Game (J) [!]"}, +{0x34495BAD, 0x502E9D26, +"Jikkyou Powerful Pro Yakyuu 4 (J) [!]"}, +{0xD7891F1C, 0xC3E43788, +"Jikkyou Powerful Pro Yakyuu 4 (J) (V1.1) [!]"}, +{0xD22943DA, 0xAC2B77C0, +"Jikkyou Powerful Pro Yakyuu 5 (J) [!]"}, +{0xB75E20B7, 0xB3FEFDFD, +"Jikkyou Powerful Pro Yakyuu (J) [!]"}, +{0xF468118C, 0xE32EE44E, +"PD Ultraman Battle Collection 64 (J) [!]"}, +{0xC83CEB83, 0xFDC56219, +"Penny Racers (E) [!]"}, +{0x73ABB1FB, 0x9CCA6093, +"Penny Racers (U) [!]"}, +{0xE4B08007, 0xA602FF33, +"Perfect Dark (E) [!]"}, +{0x96747EB4, 0x104BB243, +"Perfect Dark (J) [!]"}, +{0xDDF460CC, 0x3CA634C0, +"Perfect Dark (U) (V1.0) [!]"}, +{0x41F2B98F, 0xB458B466, +"Perfect Dark (U) (V1.1) [!]"}, +{0xEE08C602, 0x6BC2D5A6, +"PGA European Tour (E) [!]"}, +{0xB54CE881, 0xBCCB6126, +"PGA European Tour (U) [!]"}, +{0x3F245305, 0xFC0B74AA, +"Pikachu Genki Dechu (J) [!]"}, +{0x1AA05AD5, 0x46F52D80, +"Pilotwings 64 (E) [!]"}, +{0x09CC4801, 0xE42EE491, +"Pilotwings 64 (J) [!]"}, +{0xC851961C, 0x78FCAAFA, +"Pilotwings 64 (U) [!]"}, +{0xEC0F690D, 0x32A7438C, +"Pocket Monsters Snap (J) [!]"}, +{0x665E8259, 0xD098BD1D, +"Pocket Monsters Stadium (J) [!]"}, +{0x63775886, 0x5FB80E7B, +"Pocket Monsters Stadium 2 (J) [!]"}, +{0x4A1CD153, 0xD830AEF8, +"Pokemon Puzzle League (E) [!]"}, +{0x3EB2E6F3, 0x062F9EFE, +"Pokemon Puzzle League (F) [!]"}, +{0x7A4747AC, 0x44EEEC23, +"Pokemon Puzzle League (G) [!]"}, +{0x19C553A7, 0xA70F4B52, +"Pokemon Puzzle League (U) [!]"}, +{0x7BB18D40, 0x83138559, +"Pokemon Snap (A) [!]"}, +{0x4FF5976F, 0xACF559D8, +"Pokemon Snap (E) [!]"}, +{0xBA6C293A, 0x9FAFA338, +"Pokemon Snap (F) [!]"}, +{0x5753720D, 0x2A8A884D, +"Pokemon Snap (G) [!]"}, +{0xC0C85046, 0x61051B05, +"Pokemon Snap (I) [!]"}, +{0x817D286A, 0xEF417416, +"Pokemon Snap (S) [!]"}, +{0xCA12B547, 0x71FA4EE4, +"Pokemon Snap (U) [!]"}, +{0x39119872, 0x07722E9F, +"Pokemon Snap Station (U) [!]"}, +{0x1A122D43, 0xC17DAF0F, +"Pokemon Stadium - Kiosk (U) (V1.1) [!]"}, +{0x84077275, 0x57315B9C, +"Pokemon Stadium (E) [!]"}, +{0x91C9E05D, 0xAD3AAFB9, +"Pokemon Stadium (E) (V1.1)"}, +{0xA23553A3, 0x42BF2D39, +"Pokemon Stadium (F) [!]"}, +{0x42011E1B, 0xE3552DB5, +"Pokemon Stadium (G) [!]"}, +{0xA53FA82D, 0xDAE2C15D, +"Pokemon Stadium (I)"}, +{0xB6E549CE, 0xDC8134C0, +"Pokemon Stadium (S) [!]"}, +{0x90F5D9B3, 0x9D0EDCF0, +"Pokemon Stadium (U) [!]"}, +{0x2952369C, 0xB6E4C3A8, +"Pokemon Stadium 2 (E) [!]"}, +{0xAC5AA5C7, 0xA9B0CDC3, +"Pokemon Stadium 2 (F) [!]"}, +{0x439B7E7E, 0xC1A1495D, +"Pokemon Stadium 2 (G) [!]"}, +{0xEFCEAF00, 0x22094848, +"Pokemon Stadium 2 (I)"}, +{0xD0A1FC5B, 0x2FB8074B, +"Pokemon Stadium 2 (S) [!]"}, +{0x03571182, 0x892FD06D, +"Pokemon Stadium 2 (U) [!]"}, +{0xEE4FD7C2, 0x9CF1D938, +"Pokemon Stadium GS (J) [!]"}, +{0x41380792, 0xA167E045, +"Polaris Sno Cross (U) [!]"}, +{0xD7A6DCFA, 0xCCFEB6B7, +"Power League Baseball 64 (J) [!]"}, +{0x39F60C11, 0xAB2EBA7D, +"Power Rangers - Lightspeed Rescue (E) [!]"}, +{0xCF8957AD, 0x96D57EA9, +"Power Rangers - Lightspeed Rescue (U) [!]"}, +{0xFC74D475, 0x9A0278AB, +"Powerpuff Girls, The - Chemical X-traction (U) [!]"}, +{0xF3D27F54, 0xC111ACF9, +"Premier Manager 64 (E) [!]"}, +{0x9BA10C4E, 0x0408ABD3, +"Pro Mahjong Kiwame 64 (J) [!]"}, +{0x1BDCB30F, 0xA132D876, +"Pro Mahjong Tsuwamono 64 (J)"}, +{0x4B4672B9, 0x2DBE5DE7, +"Puyo Puyo 4 - Puyo Puyo Party (J) [!]"}, +{0x94807E6B, 0x60CC62E4, +"Puyo Puyo Sun 64 (J) [!]"}, +{0xC0DE0747, 0xA2DF72D3, +"Puzzle Bobble 64 (J) [!]"}, +{0x4BBBA2E2, 0x8BF3BBB2, +"Puzzle Master 64 by Michael Searl (PD)"}, +{0x16931D74, 0x65DC6D34, +"Quake 64 (E) [!]"}, +{0x9F5BF79C, 0xD2FE08A0, +"Quake 64 (U) [!]"}, +{0x7433D9D7, 0x2C4322D0, +"Quake II (E) [!]"}, +{0xBDA8F143, 0xB1AF2D62, +"Quake II (U) [!]"}, +{0xC8BB4DD9, 0xCC5F430B, +"Quest 64 (U) [!]"}, +{0x28705FA5, 0xB509690E, +"Racing Simulation - Monaco Grand Prix (E) [!]"}, +{0x2877AC2D, 0xC3DC139A, +"Racing Simulation 2 (G) [!]"}, +{0x67D21868, 0xC5424061, +"Rakuga Kids (E) [!]"}, +{0x9F1ECAF0, 0xEEC48A0E, +"Rakuga Kids (J) [!]"}, +{0x35D9BA0C, 0xDF485586, +"Rally '99 (J) [!]"}, +{0x73A88E3D, 0x3AC5C571, +"Rally Challenge 2000 (U) [!]"}, +{0x84D44448, 0x67CA19B0, +"Rampage - World Tour (E) [!]"}, +{0xC29FF9E4, 0x264BFE7D, +"Rampage - World Tour (U) [!]"}, +{0x5DFC4249, 0x99529C07, +"Rampage 2 - Universal Tour (E) [!]"}, +{0x673D099B, 0xA4C808DE, +"Rampage 2 - Universal Tour (U) [!]"}, +{0x20FD0BF1, 0xF5CF1D87, +"Rat Attack (E) [!]"}, +{0x0304C48E, 0xAC4001B8, +"Rat Attack (U) [!]"}, +{0x60D5E10B, 0x8BEDED46, +"Rayman 2 - The Great Escape (E) [!]"}, +{0xF3C5BF9B, 0x160F33E2, +"Rayman 2 - The Great Escape (U) [!]"}, +{0x3918834A, 0x15B50C29, +"Razor Freestyle Scooter (U) [!]"}, +{0x8BD4A334, 0x1E138B05, +"Ready 2 Rumble Boxing (E) [!]"}, +{0xEAB7B429, 0xBAC92C57, +"Ready 2 Rumble Boxing (U) [!]"}, +{0xE9219533, 0x13FBAFBD, +"Ready 2 Rumble Boxing Round 2 (U) [!]"}, +{0x9B500E8E, 0xE90550B3, +"Resident Evil 2 (E) [!]"}, +{0xAA18B1A5, 0x07DB6AEB, +"Resident Evil 2 (U) [!]"}, +{0xC3E7E29E, 0x5D7251CC, +"Re-Volt (E) [!]"}, +{0x0F1FA987, 0xBFC1AFA6, +"Re-Volt (U) [!]"}, +{0x02D8366A, 0x6CABEF9C, +"Road Rash 64 (E) [!]"}, +{0xF050746C, 0x247B820B, +"Road Rash 64 (U) [!]"}, +{0x74E87A70, 0x6293AED4, +"Roadsters (E) [!]"}, +{0x0B6B4DDB, 0x9671E682, +"Roadsters (U) [!]"}, +{0x272B690F, 0xAD0A7A77, +"Robot Ponkottsu 64 - Caramel of the 7 Seas (J) [!]"}, +{0x75A0B893, 0x4CA321B5, +"Robotech - Crystal Dreams (U) (beta)"}, +{0x9FF69D4F, 0x195F0059, +"Robotron 64 (E) [!]"}, +{0xAC8E4B32, 0xE7B47326, +"Robotron 64 (U) [!]"}, +{0x9FD375F8, 0x45F32DC8, +"Rocket - Robot on Wheels (E) [!]"}, +{0x0C5EE085, 0xA167DD3E, +"Rocket - Robot on Wheels (U) [!]"}, +{0xD666593B, 0xD7A25C07, +"Rockman Dash (J) [!]"}, +{0xFEE97010, 0x4E94A9A0, +"RR64 - Ridge Racer 64 (E) [!]"}, +{0x2500267E, 0x2A7EC3CE, +"RR64 - Ridge Racer 64 (U) [!]"}, +{0x658F8F37, 0x1813D28D, +"RTL World League Soccer 2000 (G) [!]"}, +{0x0C02B3C5, 0x9E2511B8, +"Rugrats - Scavenger Hunt (U) [!]"}, +{0x4D3ADFDA, 0x7598FCAE, +"Rugrats - Treasure Hunt (E) [!]"}, +{0x451ACA0F, 0x7863BC8A, +"Rugrats - Die große Schatzsuche (G)"}, +{0x0AC61D39, 0xABFA03A6, +"Rugrats in Paris - The Movie (E) [!]"}, +{0x1FC21532, 0x0B6466D4, +"Rugrats in Paris - The Movie (U) [!]"}, +{0xB7CF2136, 0xFA0AA715, +"Rush 2 - Extreme Racing USA (E) [!]"}, +{0xEDD6E031, 0x68136013, +"Rush 2 - Extreme Racing USA (U) [!]"}, +{0x918E2D60, 0xF865683E, +"S.C.A.R.S. (E) [!]"}, +{0x769147F3, 0x2033C10E, +"S.C.A.R.S. (U) [!]"}, +{0x61D116B0, 0xFA24D60C, +"San Francisco Rush - Extreme Racing (E) [!]"}, +{0x2A6B1820, 0x6ABCF466, +"San Francisco Rush - Extreme Racing (U) [!]"}, +{0x51D29418, 0xD5B46AE3, +"San Francisco Rush 2049 (E) [!]"}, +{0xB9A9ECA2, 0x17AAE48E, +"San Francisco Rush 2049 (U) [!]"}, +{0xE3BD221D, 0x3C0834D3, +"Scooby-Doo - Classic Creep Capers (E) [!]"}, +{0x0C814EC4, 0x58FE5CA8, +"Scooby-Doo - Classic Creep Capers (U) [!]"}, +{0xEBF5F6B7, 0xC956D739, +"SD Hiryuu no Ken Densetsu (J) [!]"}, +{0x60C437E5, 0xA2251EE3, +"Shadow Man (E) [!]"}, +{0xEA06F8C3, 0x07C2DEED, +"Shadow Man (F) [!]"}, +{0x84D5FD75, 0xBBFD3CDF, +"Shadow Man (G) [!]"}, +{0x3A4760B5, 0x2D74D410, +"Shadow Man (U) [!]"}, +{0xD84EEA84, 0x45B2F1B4, +"Shadowgate 64 - Trials of the Four Towers (E) [!]"}, +{0x2BC1FCF2, 0x7B9A0DF4, +"Shadowgate 64 - Trials of the Four Towers (FGD) [!]"}, +{0x02B46F55, 0x61778D0B, +"Shadowgate 64 - Trials of the Four Towers (IS)"}, +{0xCCEDB696, 0xD3883DB4, +"Shadowgate 64 - Trials of the Four Towers (J) [!]"}, +{0x036897CE, 0xE0D4FA54, +"Shadowgate 64 - Trials of the Four Towers (U) [!]"}, +{0xB1D5280C, 0x4BA7BC2A, +"Sim City 2000 (J) [!]"}, +{0xB6BC0FB0, 0xE3812198, +"Sin and Punishment - Tsumi To Batsu (J) [!]"}, +{0x2EF4D519, 0xC64A0C5E, +"Snow Speeder (J) [!]"}, +{0x5FD7CDA0, 0xD9BB51AD, +"Snowboard Kids (E) [!]"}, +{0xDBF4EA9D, 0x333E82C0, +"Snowboard Kids (U) [!]"}, +{0x84FC04FF, 0xB1253CE9, +"Snowbow Kids (J) [!]"}, +{0xC2751D1A, 0xF8C19BFF, +"Snowboard Kids 2 (E) [!]"}, +{0x930C29EA, 0x939245BF, +"Snowboard Kids 2 (U) [!]"}, +{0x22212351, 0x4046594B, +"Sonic Wings Assault (J) [!]"}, +{0xC00CA948, 0x8E60D34B, +"South Park - Chef's Luv Shack (E) [!]"}, +{0xC00CA948, 0x8E60D34B, +"South Park - Chef's Luv Shack (U) [!]"}, +{0x20B53662, 0x7B61899F, +"South Park (E) [!]"}, +{0x91B66D42, 0x16AC4E46, +"South Park (G) [!]"}, +{0x7ECBE939, 0x3C331795, +"South Park (U) [!]"}, +{0x4F8AFC3A, 0xF7912DF2, +"South Park Rally (E) [!]"}, +{0x07F3B276, 0xEC8F3D39, +"South Park Rally (U) [!]"}, +{0x37463412, 0xEAC5388D, +"Space Dynamites (J) [!]"}, +{0xEBFE2397, 0xFF74DA34, +"Space Invaders (U) [!]"}, +{0xFC70E272, 0x08FFE7AA, +"Spacestation Silicon Valley (E)/(F) [!]"}, +{0xBFE23884, 0xEF48EAAF, +"Spacestation Silicon Valley (J) [!]"}, +{0xBFE23884, 0xEF48EAAF, +"Spacestation Silicon Valley (U) [!]"}, +{0xA60ED171, 0x3D85D06E, +"Spider-Man (U) [!]"}, +{0x0DED0568, 0x1502515E, +"St. Andrews Old Course (J) [!]"}, +{0xFFCAA7C1, 0x68858537, +"Star Fox 64 (J) [!]"}, +{0xA7D015F8, 0x2289AA43, +"Star Fox 64 (U) [!]"}, +{0xBA780BA0, 0x0F21DB34, +"Star Fox 64 (U) (V1.1)"}, +{0xB703EB23, 0x28AAE53A, +"Star Soldier Vanishing Earth (J) [!]"}, +{0xDDD93C85, 0xDAE381E8, +"Star Soldier Vanishing Earth (U) [!]"}, +{0xF163A242, 0xF2449B3B, +"Star Twins (J) [!]"}, +{0x7EE0E8BB, 0x49E411AA, +"Star Wars - Rogue Squadron (E) [!]"}, +{0x219191C1, 0x33183C61, +"Star Wars - Rogue Squadron (E) (V1.1)"}, +{0x66A24BEC, 0x2EADD94F, +"Star Wars - Rogue Squadron (U) [!]"}, +{0x4D486681, 0xAB7D9245, +"Star Wars - Shadows of the Empire (E) [!]"}, +{0xFE24AC63, 0x1B41AA17, +"Star Wars - Shadows of the Empire (J) [!]"}, +{0x264D7E5C, 0x18874622, +"Star Wars - Shadows of the Empire (U) (V1.0) [!]"}, +{0x4147B091, 0x63251060, +"Star Wars - Shadows of the Empire (U) (V1.1) [!]"}, +{0x4DD7ED54, 0x74F9287D, +"Star Wars - Shadows of the Empire (U) (V1.2) [!]"}, +{0x827E4890, 0x958468DC, +"Star Wars - Shuggeki Rogue Chitai (J) [!]"}, +{0xEAE6ACE2, 0x020B4384, +"Star Wars Episode I - Battle for Naboo (E) [!]"}, +{0x3D02989B, 0xD4A381E2, +"Star Wars Episode I - Battle for Naboo (U) [!]"}, +{0x53ED2DC4, 0x06258002, +"Star Wars Episode I - Racer (E) [!]"}, +{0x61F5B152, 0x046122AB, +"Star Wars Episode I - Racer (J) [!]"}, +{0x72F70398, 0x6556A98B, +"Star Wars Episode I - Racer (U) [!]"}, +{0xBC9B2CC3, 0x4ED04DA5, +"StarCraft 64 (E) [!]"}, +{0x42CF5EA3, 0x9A1334DF, +"StarCraft 64 (E) [!]"}, +{0x0684FBFB, 0x5D3EA8A5, +"StarCraft 64 (U) [!]"}, +{0xBC9B2CC3, 0x4ED04DA5, +"StarCraft 64 (Beta)"}, +{0xD89E0E55, 0xB17AA99A, +"Starshot - Space Circus Fever (E) [!]"}, +{0x94EDA5B8, 0x8673E903, +"Starshot - Space Circus Fever (U) [!]"}, +{0x9510D8D7, 0x35100DD2, +"Stunt Racer 64 (U) [!]"}, +{0xF4646B69, 0xC5751095, +"Super B-Daman - Battle Phoenix 64 (J) [!]"}, +{0xF3F2F385, 0x6E490C7F, +"Super Bowling (J) [!]"}, +{0xAA1D215A, 0x91CBBE9A, +"Super Bowling 64 (U) [!]"}, +{0xA03CF036, 0xBCC1C5D2, +"Super Mario 64 (E) [!]"}, +{0x4EAA3D0E, 0x74757C24, +"Super Mario 64 (J) [!]"}, +{0x635A2BFF, 0x8B022326, +"Super Mario 64 (U) [!]"}, +{0xD6FBA4A8, 0x6326AA2C, +"Super Mario 64 Shindou Edition (J) [!]"}, +{0x66572080, 0x28E348E1, +"Super Robot Spirits (J) [!]"}, +{0x1649D810, 0xF73AD6D2, +"Super Robot Taisen 64 (J) [!]"}, +{0xDD26FDA1, 0xCB4A6BE3, +"Super Smash Bros. (A) [!]"}, +{0x93945F48, 0x5C0F2E30, +"Super Smash Bros. (E) [!]"}, +{0x916B8B5B, 0x780B85A4, +"Super Smash Bros. (U) [!]"}, +{0x9CE02E22, 0x206EF1B0, +"Super Speed Race 64 (J) [!]"}, +{0x2CBB127F, 0x09C2BFD8, +"Supercross 2000 (E) [!]"}, +{0xC1452553, 0x5D7B24D9, +"Supercross 2000 (U) [!]"}, +{0xB44CAB74, 0x07029A29, +"Superman (E) [!]"}, +{0xA2E8F35B, 0xC9DC87D9, +"Superman (U) [!]"}, +{0x35E811F3, 0x99792724, +"Susume! Taisen Puzzle Dama Toukon! Marumata Chou (J) [!]"}, +{0xAEBCDD54, 0x15FF834A, +"Taz Express (E) [!]"}, +{0xD9042FBB, 0xFCFF997C, +"Telefoot Soccer 2000 (F) [!]"}, +{0x963ADBA6, 0xF7D5C89B, +"Tetris 64 (J) [!]"}, +{0x0FE684A9, 0x8BB77AC4, +"Tetrisphere (E) [!]"}, +{0x3C1FDABE, 0x02A4E0BA, +"Tetrisphere (U) [!]"}, +{0xE0C4F72F, 0x769E1506, +"Tigger's Honey Hunt (E) [!]"}, +{0x4EBFDD33, 0x664C9D84, +"Tigger's Honey Hunt (U) [!]"}, +{0x2B4F4EFB, 0x43C511FE, +"Tom and Jerry in Fists of Furry (E) [!]"}, +{0x63E7391C, 0xE6CCEA33, +"Tom and Jerry in Fists of Furry (U) [!]"}, +{0x4875AF3D, 0x9A66D3A2, +"Tom Clancy's Rainbow Six (E) [!]"}, +{0x486BF335, 0x034DCC81, +"Tom Clancy's Rainbow Six (F)"}, +{0x8D412933, 0x588F64DB, +"Tom Clancy's Rainbow Six (G) [!]"}, +{0x392A0C42, 0xB790E77D, +"Tom Clancy's Rainbow Six (U) [!]"}, +{0x093F916E, 0x4408B698, +"Tonic Trouble (E) [!]"}, +{0xEF9E9714, 0xC03B2C7D, +"Tonic Trouble (U) (V1.1) [!]"}, +{0x9F8926A5, 0x0587B409, +"Tony Hawk's Pro Skater (E) [!]"}, +{0x204EC022, 0xB119D185, +"Tony Hawk's Pro Skater (U) [!]"}, +{0xE0144180, 0x650B78C9, +"Tony Hawk's Pro Skater (V1.1) [!]"}, +{0x84EAB557, 0xC88A190F, +"Tony Hawk's Pro Skater 2 (E) [!]"}, +{0x99150E18, 0x1266E6A5, +"Tony Hawk's Pro Skater 2 (U) [!]"}, +{0x1A7F70B5, 0x00B7B9FD, +"Tony Hawk's Pro Skater 3 (U)"}, +{0x5F3F49C6, 0x0DC714B0, +"Top Gear Hyper-Bike (E) [!]"}, +{0x845B0269, 0x57DE9502, +"Top Gear Hyper-Bike (J) [!]"}, +{0x8ECC02F0, 0x7F8BDE81, +"Top Gear Hyper-Bike (U) [!]"}, +{0xD09BA538, 0x1C1A5489, +"Top Gear Overdrive (E) [!]"}, +{0x0578F24F, 0x9175BF17, +"Top Gear Overdrive (J) [!]"}, +{0xD741CD80, 0xACA9B912, +"Top Gear Overdrive (U) [!]"}, +{0x7F43E701, 0x536328D1, +"Top Gear Rally (E) [!]"}, +{0x0E596247, 0x753D4B8B, +"Top Gear Rally (J) [!]"}, +{0x62269B3D, 0xFE11B1E8, +"Top Gear Rally (U) [!]"}, +{0xBEBAB677, 0x51B0B5E4, +"Top Gear Rally 2 (E) [!]"}, +{0xF82DD377, 0x8C3FB347, +"TG Rally 2 (UK Version)"}, +{0xCFEF2CD6, 0xC9E973E6, +"Top Gear Rally 2 (J) [!]"}, +{0xBE5973E0, 0x89B0EDB8, +"Top Gear Rally 2 (U) [!]"}, +{0xEF703CA4, 0x4D4A9AC9, +"Toukon Road - Brave Spirits (J) [!]"}, +{0x551C7F43, 0x9149831C, +"Toukon Road 2 - The Next Generation (J) [!]"}, +{0xCCEB3858, 0x26952D97, +"Toy Story 2 (E) [!]"}, +{0xCB93DB97, 0x7F5C63D5, +"Toy Story 2 (F) [!]"}, +{0x782A9075, 0xE552631D, +"Toy Story 2 (G) [!]"}, +{0xA150743E, 0xCF2522CD, +"Toy Story 2 (U) [!]"}, +{0xFE4B6B43, 0x081D29A7, +"Triple Play 2000 (U) [!]"}, +{0x2F7009DD, 0xFC3BAC53, +"Turok - Dinosaur Hunter (E) (V1.0) [!]"}, +{0x665F09DD, 0xFC3BAC53, +"Turok - Dinosaur Hunter (E) (V1.0) [a1]"}, +{0x2F700DCD, 0x176CC5C9, +"Turok - Dinosaur Hunter (E) (V1.1)/(V1.2) [!]"}, +{0x665FD963, 0xB5CC6612, +"Turok - Dinosaur Hunter (G) [!]"}, +{0x916AE6B8, 0x8817AB22, +"Turok - Dinosaur Hunter (J) [!]"}, +{0x2F70F10D, 0x5C4187FF, +"Turok - Dinosaur Hunter (U) (V1.0) [!]"}, +{0x2F700DCD, 0x176CC5C9, +"Turok - Dinosaur Hunter (U) (V1.1)/(v1.2) [!]"}, +{0x66E4FA0F, 0xDE88C7D0, +"Turok - Legenden des Verlorenen Landes (Rage Wars) (G) [!]"}, +{0x1EA26214, 0xE790900F, +"Turok - Rage Wars (E) [!]"}, +{0x2E0E7749, 0xB8B49D59, +"Turok 2 - Seeds of Evil (FIS)"}, +{0xADB9498B, 0xDAF28F55, +"Turok - Rage Wars (U) [!]"}, +{0xE8C95AFC, 0x35D121DA, +"Turok 2 - Seeds of Evil - Kiosk (E) [!]"}, +{0xE8C95AFC, 0x35D121DA, +"Turok 2 - Seeds of Evil - Kiosk (U) [!]"}, +{0xE0B92B94, 0x80E87CBD, +"Turok 2 - Seeds of Evil (E) [!]"}, +{0xFE05840B, 0x9393320C, +"Turok 2 - Seeds of Evil (G) [!]"}, +{0x2E0E7749, 0xB8B49D59, +"Turok 2 - Seeds of Evil (FIS)"}, +{0x49088A11, 0x6494957E, +"Turok 2 - Seeds of Evil (U) [!]"}, +{0x6A162FF2, 0x2093704C, +"Turok 3 - Shadow of Oblivion (E) [!]"}, +{0x89A579F1, 0x667E97EF, +"Turok 3 - Shadow of Oblivion (U) [!]"}, +{0xE688A5B8, 0xB14B3F18, +"Twisted Edge Extreme Snowboarding (E) [!]"}, +{0xBBC99D32, 0x117DAA80, +"Twisted Edge Extreme Snowboarding (U) [!]"}, +{0xDD10BC7E, 0xF900B351, +"Vigilante 8 - 2nd Offence (E) [!]"}, +{0xF5C5866D, 0x052713D9, +"Vigilante 8 - 2nd Offense (U) [!]"}, +{0x151F79F4, 0x8EEDC8E5, +"Vigilante 8 (E) [!]"}, +{0xE2BC82A2, 0x591CD694, +"Vigilante 8 (F) [!]"}, +{0x6EDA5178, 0xD396FEC1, +"Vigilante 8 (G) [!]"}, +{0xEA71056A, 0xE4214847, +"Vigilante 8 (U) [!]"}, +{0x60006C98, 0x2605A381, +"Violence Killer - Turok New Generation (J) [!]"}, +{0x2FDAA221, 0xA588A7CE, +"Virtual Chess 64 (E) [!]"}, +{0x82B3248B, 0xE73E244D, +"Virtual Chess 64 (U) [!]"}, +{0x98F9F2D0, 0x03D9F09C, +"Virtual Pool 64 (E) [!]"}, +{0x4E4A7643, 0xA37439D7, +"Virtual Pool 64 (U) [!]"}, +{0x045C08C4, 0x4AFD798B, +"Virtual Pro Wrestling (J) [!]"}, +{0xCD094235, 0x88074B62, +"Virtual Pro Wrestling 2 (J) [!]"}, +{0x636E6B19, 0xE57DDC5F, +"V-Rally Edition 99 (E) [!]"}, +{0x4D0224A5, 0x1BEB5794, +"V-Rally Edition 99 (J) [!]"}, +{0x3C059038, 0xC8BF2182, +"V-Rally Edition 99 (U) [!]"}, +{0x93053075, 0x261E0F43, +"Waialae Country Club-True Golf Classics (E) (V1.0) [!]"}, +{0x0C5057AD, 0x046E126E, +"Waialae Country Club-True Golf Classics (E) (V1.1) [!]"}, +{0x8066D58A, 0xC3DECAC1, +"Waialae Country Club-True Golf Classics (U) [!]"}, +{0xD715CC70, 0x271CF5D6, +"War Gods (E) [!]"}, +{0xF7FE28F6, 0xC3F2ACC3, +"War Gods (U) [!]"}, +{0x650EFA96, 0x30DDF9A7, +"Wave Race 64 (E) [!]"}, +{0x5C9191D6, 0xB30AC306, +"Wave Race 64 (J) [!]"}, +{0x44995484, 0x20A5FC5E, +"Wave Race 64 (J) (V1.1) [!]"}, +{0x7DE11F53, 0x74872F9D, +"Wave Race 64 (U) (V1.0) [!]"}, +{0x492F4B61, 0x04E5146A, +"Wave Race 64 (U) (V1.1) [!]"}, +{0x535DF3E2, 0x609789F1, +"Wave Race 64 Shindou Edition (J) (V1.2) [!]"}, +{0x2209094B, 0x2C9559AF, +"Wayne Gretzky's 3D Hockey (E) [!]"}, +{0xF1301043, 0xFD80541A, +"Wayne Gretzky's 3D Hockey (J) [!]"}, +{0x6B45223F, 0xF00E5C56, +"Wayne Gretzky's 3D Hockey (U) [!]"}, +{0xDC3BAA59, 0x0ABB456A, +"Wayne Gretzky's 3D Hockey (U) (V1.1)"}, +{0x661B45F3, 0x9ED6266D, +"Wayne Gretzky's 3D Hockey '98 (E) [!]"}, +{0x5A9D3859, 0x97AAE710, +"Wayne Gretzky's 3D Hockey '98 (U) [!]"}, +{0x396F5ADD, 0x6693ECA7, +"WCW Backstage Assault (U) [!]"}, +{0xAA7B0658, 0x9C96937B, +"WCW Mayhem (E) [!]"}, +{0x33BE8CD6, 0xEC186912, +"WCW Mayhem (U) [!]"}, +{0xD4C45A1A, 0xF425B25E, +"WCW Nitro (U) [!]"}, +{0x8BDBAF68, 0x345B4B36, +"WCW vs. nWo - World Tour (E) [!]"}, +{0x2C3E19BD, 0x5113EE5E, +"WCW vs. nWo - World Tour (U) (V1.0) [!]"}, +{0x71BE60B9, 0x1DDBFB3C, +"WCW vs. nWo - World Tour (U) (V1.1) [!]"}, +{0x68E8A875, 0x0CE7A486, +"WCW-nWo Revenge (E) [!]"}, +{0xDEE596AB, 0xAF3B7AE7, +"WCW-nWo Revenge (U) [!]"}, +{0xCEA8B54F, 0x7F21D503, +"Wetrix (E) [!]"}, +{0xDCB6EAFA, 0xC6BBCFA3, +"Wetrix (J) [!]"}, +{0xCEA8B54F, 0x7F21D503, +"Wetrix (U) [!]"}, +{0xE896092B, 0xDC244D4E, +"Wheel of Fortune (U) [!]"}, +{0x0CEBC4C7, 0x0C9CE932, +"Wild Choppers (J) [!]"}, +{0xD5898CAF, 0x6007B65B, +"WinBack - Covert Operations (E) [!]"}, +{0x1FA056E0, 0xA4B9946A, +"WinBack - Covert Operations (J) [!]"}, +{0xED98957E, 0x8242DCAC, +"WinBack - Covert Operations (U) [!]"}, +{0x54310E7D, 0x6B5430D8, +"Wipeout 64 (E) [!]"}, +{0x132D2732, 0xC70E9118, +"Wipeout 64 (U) [!]"}, +{0xE43C9765, 0x05B1C1BE, +"Wonder Project J2 (J) [!]"}, +{0xF9FC3090, 0xFF014EC2, +"World Cup 98 (E) [!]"}, +{0xBD636D6A, 0x5D1F54BA, +"World Cup 98 (U) [!]"}, +{0xAC062778, 0xDFADFCB8, +"World Driver Championship (E) [!]"}, +{0x308DFEC8, 0xCE2EB5F6, +"World Driver Championship (U) [!]"}, +{0x3B941695, 0xF90A5EEB, +"World is Not Enough, The (E) [!]"}, +{0x033F4C13, 0x319EE7A7, +"World is Not Enough, The (U) [!]"}, +{0x2D21C57B, 0x8FE4C58C, +"Worms - Armageddon (E) [!]"}, +{0x13E959A0, 0x0E93CAB0, +"Worms - Armageddon (U) [!]"}, +{0x33A275A4, 0xB8504459, +"WWF - War Zone (E) [!]"}, +{0xCD5BEC0F, 0x86FD1008, +"WWF - War Zone (U) [!]"}, +{0x5BF45B7B, 0x596BEEE8, +"WWF Attitude (E) [!]"}, +{0x8F3151C8, 0x4F3AF545, +"WWF Attitude (G) [!]"}, +{0xD2BE2F14, 0x38453788, +"WWF Attitude (U) [!]"}, +{0x6D8DF08E, 0xD008C3CF, +"WWF No Mercy (E) (V1.0) [!]"}, +{0x8CDB94C2, 0xCB46C6F0, +"WWF No Mercy (E) (V1.1) [!]"}, +{0x4E4B0640, 0x1B49BCFB, +"WWF No Mercy (U) [!]"}, +{0xC71353BE, 0xAA09A6EE, +"WWF WrestleMania 2000 (E) [!]"}, +{0x12737DA5, 0x23969159, +"WWF Wrestlemania 2000 (J) [!]"}, +{0x90A59003, 0x31089864, +"WWF WrestleMania 2000 (U) [!]"}, +{0x0A1667C7, 0x293346A6, +"Xena Warrior Princess - Talisman of Fate (E) [!]"}, +{0x0553AE9D, 0xEAD8E0C1, +"Xena Warrior Princess - Talisman of Fate (U) [!]"}, +{0x9F8B96C3, 0xA01194DC, +"Yakouchuu II - Satsujun Kouru (J) [!]"}, +{0xD3F97D49, 0x6924135B, +"Yoshi's Story (E) [!]"}, +{0x2DCFCA60, 0x8354B147, +"Yoshi's Story (J) [!]"}, +{0x2337D8E8, 0x6B8E7CEC, +"Yoshi's Story (U) [!]"}, +{0x77DA3B8D, 0x162B0D7C, +" Yousuke Ide's Mahjong School (J) [!]"}, +{0x9FE6162D, 0xE97E4037, +"Yuke Yuke!! Trouble Makers (J) [!]"}, +{0xEC7011B7, 0x7616D72B, +"Zelda no Densetsu - Toki no Ocarina (J) (V1.0)"}, +{0xD43DA81F, 0x021E1E19, +"Zelda no Densetsu - Toki no Ocarina (J) (V1.1)"}, +{0x693BA2AE, 0xB7F14E9F, +"Zelda no Densetsu - Toki no Ocarina (J) (V1.2)"}, +{0xF7F52DB8, 0x2195E636, +"Zelda no Densetsu - Toki no Ocarina - Zelda Collection Version (J) (GC Version)"}, +{0xF43B45BA, 0x2F0E9B6F, +"Zelda no Densetsu - Toki no Ocarina GC Ura (J) (GC Version)"}, +{0xF611F4BA, 0xC584135C, +"Zelda no Densetsu - Toki no Ocarina GC (J) (GC Version)"}, +{0xEC417312, 0xEB31DE5F, +"Zelda no Densetsu - Mujura no Kamen (J) (V1.0)"}, +{0x69AE0438, 0x2C63F3F3, +"Zelda no Densetsu - Mujura no Kamen (J) (V1.1)"}, +{0x8473D0C1, 0x23120666, +"Zelda no Densetsu - Mujura no Kamen - Zelda Collection Version (J) (GC Version)"}, +{0x1C010CCD, 0x22D3B7FA, +"Zool - Majou Tsukai Densetsu (J) [!]"}, +}; #ifdef __cplusplus } From 810ed20823ba16d0283d8e5916de9f22b3370abe Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 18 Jan 2022 08:04:22 +1030 Subject: [PATCH 110/121] TFT: Print current game name on TFT --- src/tft.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/tft.cpp b/src/tft.cpp index 4b268195..56637be0 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -262,6 +262,16 @@ void tft_force_update() n64_status.set_str(fileio_status_text); n64_status.show_window(); + //Draw the current games name + n64_status_text = n64_get_current_game(); + n64_status.set_surface(psurface_guilite); + n64_status.set_bg_color(TFT_BG_COLOR); + n64_status.set_font_color(GL_RGB(255, 255, 255)); + n64_status.set_wnd_pos(125, Arial_14_GL.height * 2, 200, Arial_14_GL.height); + n64_status.set_font_type(&Arial_14_GL); + n64_status.set_str(n64_status_text); + n64_status.show_window(); + tft_dev_draw(true); _tft_update_needed = 0; From be6837241685e4d38947cd680a135a740b004824 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 18 Jan 2022 08:10:25 +1030 Subject: [PATCH 111/121] STM32F789I: Reduce SD speed --- .../bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sd.c b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sd.c index 5ea81c4b..7d2b005e 100644 --- a/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sd.c +++ b/src/port_stm32f7/common/bsp_drivers/STM32F769I-Discovery/stm32f769i_discovery_sd.c @@ -158,7 +158,7 @@ uint8_t BSP_SD_Init(void) uSdHandle.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; uSdHandle.Init.BusWide = SDMMC_BUS_WIDE_1B; uSdHandle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; - uSdHandle.Init.ClockDiv = SDMMC_TRANSFER_CLK_DIV; + uSdHandle.Init.ClockDiv = 0x2; //48MHz / (6 + 2) = 6MHZ. Default value was unreliable for me /* Msp SD Detect pin initialization */ BSP_SD_Detect_MspInit(&uSdHandle, NULL); From af0abb5b8be7dc0f98a90c43e6979cd109d6d30b Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Tue, 18 Jan 2022 08:58:30 +1030 Subject: [PATCH 112/121] STM32F7: Move common bsp port code to folder --- platformio.ini | 2 + .../bsp_common}/fileio_stm32.cpp | 0 .../bsp_common}/memory_stm32.cpp | 0 .../bsp_common}/tft_stm32.cpp | 0 .../stm37f750-dk/memory_stm32.cpp | 75 ---------- .../stm37f769-dk/fileio_stm32.cpp | 138 ------------------ src/port_stm32f7/stm37f769-dk/tft_stm32.cpp | 88 ----------- 7 files changed, 2 insertions(+), 301 deletions(-) rename src/port_stm32f7/{stm37f750-dk => common/bsp_common}/fileio_stm32.cpp (100%) rename src/port_stm32f7/{stm37f769-dk => common/bsp_common}/memory_stm32.cpp (100%) rename src/port_stm32f7/{stm37f750-dk => common/bsp_common}/tft_stm32.cpp (100%) delete mode 100644 src/port_stm32f7/stm37f750-dk/memory_stm32.cpp delete mode 100644 src/port_stm32f7/stm37f769-dk/fileio_stm32.cpp delete mode 100644 src/port_stm32f7/stm37f769-dk/tft_stm32.cpp diff --git a/platformio.ini b/platformio.ini index d1b958db..4b19e807 100644 --- a/platformio.ini +++ b/platformio.ini @@ -110,6 +110,7 @@ src_filter = + + + + + + + @@ -137,6 +138,7 @@ src_filter = + + + + + + + + diff --git a/src/port_stm32f7/stm37f750-dk/fileio_stm32.cpp b/src/port_stm32f7/common/bsp_common/fileio_stm32.cpp similarity index 100% rename from src/port_stm32f7/stm37f750-dk/fileio_stm32.cpp rename to src/port_stm32f7/common/bsp_common/fileio_stm32.cpp diff --git a/src/port_stm32f7/stm37f769-dk/memory_stm32.cpp b/src/port_stm32f7/common/bsp_common/memory_stm32.cpp similarity index 100% rename from src/port_stm32f7/stm37f769-dk/memory_stm32.cpp rename to src/port_stm32f7/common/bsp_common/memory_stm32.cpp diff --git a/src/port_stm32f7/stm37f750-dk/tft_stm32.cpp b/src/port_stm32f7/common/bsp_common/tft_stm32.cpp similarity index 100% rename from src/port_stm32f7/stm37f750-dk/tft_stm32.cpp rename to src/port_stm32f7/common/bsp_common/tft_stm32.cpp diff --git a/src/port_stm32f7/stm37f750-dk/memory_stm32.cpp b/src/port_stm32f7/stm37f750-dk/memory_stm32.cpp deleted file mode 100644 index 71a58793..00000000 --- a/src/port_stm32f7/stm37f750-dk/memory_stm32.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#include "common.h" -#include "tinyalloc.h" -#include "memory.h" - -//Pulled in from linker. -extern uint32_t _extram_start; -extern uint32_t _extram_end; - -static uint32_t extram_start = 0; -static uint32_t extram_end = 0; - -bool memory_dev_init() -{ - extram_start = (int)&_extram_start; - extram_end = (int)&_extram_end; - - //There's 8MB usable SDRAM on the f750-k board located from 0xC0000000 - //The first 512kBytes are reversed for the LCD. extram_start starts just after this (at 0xC0080000) - //I create a new heap at this location for allocating large files - extern SDRAM_HandleTypeDef sdramHandle; - if (sdramHandle.State != HAL_SDRAM_STATE_READY) - { - BSP_SDRAM_Init(); - } - - uint32_t extram_bytes = extram_end - extram_start; - ta_init((void *)(extram_start), //Base of heap - (void *)(extram_end), //End of heap - extram_bytes / 32768, //Number of memory chunks (32k/per chunk) - 16, //Smaller chunks than this won't split - 4); //32 word size alignment - - debug_print_memory("[MEMORY] External memory initialised\n"); - debug_print_memory("[MEMORY] Detected %ukB\n", extram_bytes / 1024); - debug_print_memory("[MEMORY] Heap start: %08x\n", (void *)(extram_start)); - debug_print_memory("[MEMORY] Heap end: %08x\n", (void *)(extram_end)); - debug_print_memory("[MEMORY] Number of memory chunks: %u\n", extram_bytes / 32768); - return true; -} - -void *memory_dev_malloc(uint32_t len) -{ - void *pt = ta_alloc(len); - if (pt == NULL) - { - debug_print_error("[MEMORY] ERROR, could not allocate memory\n"); - } - return pt; -} - -void memory_dev_free(void *add) -{ - if ((uint32_t)add >= extram_start) - { - ta_free(add); - } - else - { - free(add); - } -} - -/* - * Function: Detect the amount of external RAM installed. This prints it to the LCD and a number > 0 is required for TPAK - * emulation. If you device has loads of internal RAM suitable for TPAK emulation (>2MB or so) which you want to use, set this to a non-zero number. - * ---------------------------- - * Returns: How many MB of external RAM is installed. - */ -uint8_t memory_get_ext_ram_size() -{ - return (extram_end - extram_start) / 1024 / 1024; -} diff --git a/src/port_stm32f7/stm37f769-dk/fileio_stm32.cpp b/src/port_stm32f7/stm37f769-dk/fileio_stm32.cpp deleted file mode 100644 index a3e43a7b..00000000 --- a/src/port_stm32f7/stm37f769-dk/fileio_stm32.cpp +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#include "common.h" -#include "ff.h" -#include "ff_gen_drv.h" -#include "sd_diskio.h" - -static FATFS fs; -static char SDPath[4] = {0}; -extern const Diskio_drvTypeDef SD_Driver; - -bool fileio_dev_init() -{ - if (FATFS_LinkDriver(&SD_Driver, SDPath) != 0) - { - return false; - } - - int retries = 3; - - while (retries) - { - if (f_mount(&fs, (TCHAR const *)SDPath, 1) != FR_OK) - { - retries--; - if (retries == 0) - return false; - HAL_Delay(100); - } - else - { - break; - } - } - - return f_chdir((TCHAR const *)SDPath) == FR_OK; -} - -int fileio_dev_open_dir(const char *dir) -{ - DIR *dp = (DIR *)malloc(sizeof(DIR)); - if (dp == NULL) - { - return 0; - } - n64hal_disable_interrupts(); - FRESULT res = f_opendir(dp, (const TCHAR *)dir); - n64hal_enable_interrupts(); - - if (res != FR_OK) - { - free(dp); - return 0; - } - - return (uint32_t)dp; -} - -const char *fileio_dev_get_next_filename(int handle) -{ - static FILINFO fno; - FRESULT res; - DIR *dp = (DIR *)handle; - n64hal_disable_interrupts(); - res = f_readdir(dp, &fno); - n64hal_enable_interrupts(); - if (dp && res == FR_OK && fno.fname[0] != 0) - { - return fno.fname; - } - return NULL; -} - -void fileio_dev_close_dir(int handle) -{ - if (handle == 0) - { - return; - } - - DIR *dp = (DIR *)handle; - f_closedir(dp); - free(dp); -} - -int fileio_dev_read(char *filename, uint32_t file_offset, uint8_t *data, uint32_t len) -{ - FIL fil; - FRESULT res; - UINT br; - n64hal_disable_interrupts(); - res = f_open(&fil, filename, FA_READ); - if (res != FR_OK) - { - n64hal_enable_interrupts(); - return -1; - } - - f_lseek(&fil, file_offset); - res = f_read(&fil, data, len, &br); - if (res != FR_OK || br != len) - { - f_close(&fil); - n64hal_enable_interrupts(); - return -2; - } - - f_close(&fil); - n64hal_enable_interrupts(); - return 0; -} - -int fileio_dev_write(char *filename, uint8_t *data, uint32_t len) -{ - FIL fil; - FRESULT res; - UINT bw; - n64hal_disable_interrupts(); - res = f_open(&fil, filename, FA_WRITE | FA_CREATE_ALWAYS); - if (res != FR_OK) - { - n64hal_enable_interrupts(); - return -1; - } - - res = f_write(&fil, data, len, &bw); - if (res != FR_OK || bw != len) - { - f_close(&fil); - n64hal_enable_interrupts(); - return -2; - } - - f_close(&fil); - n64hal_enable_interrupts(); - return 0; -} diff --git a/src/port_stm32f7/stm37f769-dk/tft_stm32.cpp b/src/port_stm32f7/stm37f769-dk/tft_stm32.cpp deleted file mode 100644 index 9feca6e3..00000000 --- a/src/port_stm32f7/stm37f769-dk/tft_stm32.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#include "common.h" -#include "tft.h" -#include "controller_icon.h" -#include "usb64_logo.h" -#include "GuiLite.h" - -#define TFT_FRAMEBUFFER_SIZE (TFT_WIDTH * TFT_HEIGHT * TFT_PIXEL_SIZE) -c_surface *psurface_guilite = NULL; -c_display *pdisplay_guilite = NULL; -#if TFT_USE_FRAMEBUFFER -static uint8_t *_framebuffer = (uint8_t *)(LCD_FB_START_ADDRESS); -#else -static uint8_t *_framebuffer = (uint8_t *)(LCD_FB_START_ADDRESS); -struct EXTERNAL_GFX_OP my_gfx_op; -#endif - -static void _tft_assert(const char *file, int line) -{ - debug_print_error("[TFT] Error: Assert in %s on line %d\n", file, line); - while (1) - ; -} - -static void _tft_log_out(const char *log) -{ - debug_print_status(log); -} - -#if TFT_USE_FRAMEBUFFER == 0 -static void _draw_pixel(int x, int y, unsigned int rgb) -{ - //Device specific pixel draw - BSP_LCD_DrawPixel(x, y, rgb); -} - -static void _fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) -{ - BSP_LCD_SetTextColor(rgb); - BSP_LCD_FillRect(x0, y0, x1 - x0, y1 - y0); - //Weird, but the above FillRect leaves before finshing properly. This fixes it? - BSP_LCD_FillRect(x0, y0, 1, 1); -} -#endif - -void tft_dev_draw(bool force) -{ - //Dont need to do anything. This TFT just updates from the SDRAM buffer automatically. -} - -extern "C" void BSP_LCD_ClockConfig(LTDC_HandleTypeDef *hltdc, void *Params) -{ - //Overrise the internal clock config as it messes with other clock divs and multipliers. - //Dont do anything. All clocks are setup properly at boot -} - -void tft_dev_init() -{ -#if TFT_USE_FRAMEBUFFER - static c_surface surface(TFT_WIDTH, TFT_HEIGHT, 2, Z_ORDER_LEVEL_0); - static c_display display(_framebuffer, TFT_WIDTH, TFT_HEIGHT, &surface); - psurface_guilite = &surface; - pdisplay_guilite = &display; -#else - static c_surface_no_fb surface(TFT_WIDTH, TFT_HEIGHT, 2, &my_gfx_op, Z_ORDER_LEVEL_0); - static c_display display(NULL, TFT_WIDTH, TFT_HEIGHT, &surface); - my_gfx_op.draw_pixel = _draw_pixel; - my_gfx_op.fill_rect = _fill_rect; -#endif - psurface_guilite = &surface; - pdisplay_guilite = &display; - register_debug_function(_tft_assert, _tft_log_out); -#if (ENABLE_TFT_DISPLAY >= 1) - BSP_LCD_Init(); - BSP_LCD_LayerDefaultInit(0, (uint32_t)_framebuffer); - BSP_LCD_SelectLayer(0); - BSP_LCD_SetBackColor(TFT_BG_COLOR); - BSP_LCD_Clear(TFT_BG_COLOR); - BSP_LCD_DisplayOn(); -#endif -} - -bool tft_dev_is_busy() -{ - return 0; -} From 1477c836755bbffa1d1667bc7714de668918bde6 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Sat, 15 Jan 2022 19:31:16 +0000 Subject: [PATCH 113/121] Generate hex output --- hex_from_elf.py | 10 ++++++++++ platformio.ini | 1 + 2 files changed, 11 insertions(+) create mode 100644 hex_from_elf.py diff --git a/hex_from_elf.py b/hex_from_elf.py new file mode 100644 index 00000000..3be426bc --- /dev/null +++ b/hex_from_elf.py @@ -0,0 +1,10 @@ +Import("env") + +# Custom HEX from ELF +env.AddPostAction( + "$BUILD_DIR/${PROGNAME}.elf", + env.VerboseAction(" ".join([ + "$OBJCOPY", "-O", "ihex", "-R", ".eeprom", + "$BUILD_DIR/${PROGNAME}.elf", "$BUILD_DIR/${PROGNAME}.hex" + ]), "Building $BUILD_DIR/${PROGNAME}.hex") +) \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 4b19e807..d8adca2b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -130,6 +130,7 @@ build_flags = platform = ststm32 board = disco_f769ni framework = stm32cube +extra_scripts = post:hex_from_elf.py board_build.ldscript = src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld src_filter = From a062025b89385942b0ad6b416276a97835aece77 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Thu, 20 Jan 2022 07:58:34 +1030 Subject: [PATCH 114/121] Input: Re-add RANDNET emulation --- src/input.cpp | 74 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/input.h | 8 +++--- 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/src/input.cpp b/src/input.cpp index 54f81ebb..a601654d 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -13,6 +13,27 @@ input_driver_t input_devices[MAX_USB_CONTROLLERS]; uint32_t hardwired1; +static uint8_t kb_modifier_to_key(uint8_t modifier) +{ + if (modifier & KEYBOARD_MODIFIER_LEFTCTRL) + return HID_KEY_CONTROL_LEFT; + if (modifier & KEYBOARD_MODIFIER_LEFTSHIFT) + return HID_KEY_SHIFT_LEFT; + if (modifier & KEYBOARD_MODIFIER_LEFTALT) + return HID_KEY_ALT_LEFT; + if (modifier & KEYBOARD_MODIFIER_LEFTGUI) + return HID_KEY_GUI_LEFT; + if (modifier & KEYBOARD_MODIFIER_RIGHTCTRL) + return HID_KEY_CONTROL_RIGHT; + if (modifier & KEYBOARD_MODIFIER_RIGHTSHIFT) + return HID_KEY_SHIFT_RIGHT; + if (modifier & KEYBOARD_MODIFIER_RIGHTALT) + return HID_KEY_ALT_RIGHT; + if (modifier & KEYBOARD_MODIFIER_RIGHTGUI) + return HID_KEY_GUI_RIGHT; + return 0; +} + static input_driver_t *find_slot(uint16_t uid) { //See if input device already exists @@ -265,7 +286,6 @@ uint16_t input_get_state(uint8_t id, void *response, bool *combo_pressed) //N64 report is basically a n64 controller response n64_buttonmap *state = (n64_buttonmap *)response; hid_mouse_report_t *report = (hid_mouse_report_t *)in_dev->data; - bool new_data = state->x_axis != report->x || state->y_axis != -report->y; state->dButtons = 0; state->x_axis = report->x; @@ -282,7 +302,57 @@ uint16_t input_get_state(uint8_t id, void *response, bool *combo_pressed) report->y = 0; } } - + else if (input_is(id, INPUT_KEYBOARD)) + { + n64_randnet_kb *new_state = (n64_randnet_kb *)response; + hid_keyboard_report_t *report = (hid_keyboard_report_t *)in_dev->data; + memset(new_state->buttons, 0, sizeof(new_state->buttons)); + new_state->flags = 0; + + //https://sites.google.com/site/consoleprotocols/home/nintendo-joy-bus-documentation/n64-specific/randnet-keyboard + uint8_t a = 0, b = 0, c = 0; + uint8_t mod = report->modifier; + uint8_t hid_keyboard_press = kb_modifier_to_key(mod & (1 << c)); + mod &= ~(1 << c); + while (a < RANDNET_MAX_BUTTONS && b < sizeof(report->keycode)) + { + if (hid_keyboard_press != 0) + { + //report outputs 1 if too many keys are pressed on the keyboard + if (hid_keyboard_press == 1) + { + new_state->flags |= RANDNET_FLAG_EXCESS_BUTTONS; + break; + } + //Randnet has a status flag for the home button. + if (hid_keyboard_press == HID_KEY_HOME) + { + new_state->flags |= RANDNET_FLAG_HOME_KEY; + break; + } + //Handle all other key presses + for (uint32_t d = 0; d < (sizeof(randnet_map) / sizeof(randnet_map_t)); d++) + { + if (hid_keyboard_press == randnet_map[d].keypad) + { + new_state->buttons[a++] = randnet_map[d].randnet_matrix; + break; + } + } + } + //Get the next key (modifier or normal key) + if (mod) + { + c++; + hid_keyboard_press = kb_modifier_to_key(mod & (1 << c)); + mod &= ~(1 << c); + } + else + { + hid_keyboard_press = report->keycode[b++]; + } + } + } return 1; } diff --git a/src/input.h b/src/input.h index 4a850202..d8062a96 100644 --- a/src/input.h +++ b/src/input.h @@ -9,7 +9,7 @@ typedef struct { - uint16_t keypad; + uint8_t keypad; uint16_t randnet_matrix; } randnet_map_t; @@ -86,10 +86,10 @@ static const randnet_map_t randnet_map[] PROGMEM = { {HID_KEY_MINUS, 0x1004}, //- (Long dash) {HID_KEY_ARROW_UP, 0x0204}, //Up Cursor {HID_KEY_SHIFT_RIGHT, 0x0E06}, //Right Shift - {103, 0x1107}, //Ctrl - {110, 0x0F07}, //Opt + {HID_KEY_CONTROL_LEFT, 0x1107},//Ctrl + {HID_KEY_GUI_LEFT, 0x0F07}, //Opt {HID_KEY_SEMICOLON, 0x1105}, //| (Pipes) - {105, 0x1008}, //Alt + {HID_KEY_ALT_LEFT, 0x1008}, //Alt {HID_KEY_KEYPAD_1, 0x1002}, //Japanese 'alphanumeric key' {HID_KEY_SPACE, 0x0602}, //Space {HID_KEY_KEYPAD_2, 0x0E02}, //Japanese 'kana' From 192ab749d0ee7f72ddf832f466c624b95fc73bca Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Fri, 21 Jan 2022 14:47:25 +1030 Subject: [PATCH 115/121] TFT: Scale output on large LCDs --- .../common/bsp_common/tft_stm32.cpp | 26 ++----- src/port_stm32f7/stm37f750-dk/port_conf.h | 4 +- src/port_stm32f7/stm37f769-dk/port_conf.h | 3 +- src/port_teensy41/port_conf.h | 5 +- src/port_template/port_conf.h | 78 ++++++++++--------- src/tft.cpp | 28 +++---- 6 files changed, 72 insertions(+), 72 deletions(-) diff --git a/src/port_stm32f7/common/bsp_common/tft_stm32.cpp b/src/port_stm32f7/common/bsp_common/tft_stm32.cpp index 9feca6e3..649138d7 100644 --- a/src/port_stm32f7/common/bsp_common/tft_stm32.cpp +++ b/src/port_stm32f7/common/bsp_common/tft_stm32.cpp @@ -10,12 +10,9 @@ #define TFT_FRAMEBUFFER_SIZE (TFT_WIDTH * TFT_HEIGHT * TFT_PIXEL_SIZE) c_surface *psurface_guilite = NULL; c_display *pdisplay_guilite = NULL; -#if TFT_USE_FRAMEBUFFER -static uint8_t *_framebuffer = (uint8_t *)(LCD_FB_START_ADDRESS); -#else static uint8_t *_framebuffer = (uint8_t *)(LCD_FB_START_ADDRESS); struct EXTERNAL_GFX_OP my_gfx_op; -#endif +float scale = 1; static void _tft_assert(const char *file, int line) { @@ -32,16 +29,14 @@ static void _tft_log_out(const char *log) #if TFT_USE_FRAMEBUFFER == 0 static void _draw_pixel(int x, int y, unsigned int rgb) { - //Device specific pixel draw - BSP_LCD_DrawPixel(x, y, rgb); + BSP_LCD_SetTextColor(rgb); + BSP_LCD_FillRect(x * scale, y * scale, scale + 1, scale + 1); } static void _fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) { BSP_LCD_SetTextColor(rgb); - BSP_LCD_FillRect(x0, y0, x1 - x0, y1 - y0); - //Weird, but the above FillRect leaves before finshing properly. This fixes it? - BSP_LCD_FillRect(x0, y0, 1, 1); + BSP_LCD_FillRect(x0 * scale, y0 * scale, (x1 - x0) * scale, (y1 - y0) * scale); } #endif @@ -58,17 +53,12 @@ extern "C" void BSP_LCD_ClockConfig(LTDC_HandleTypeDef *hltdc, void *Params) void tft_dev_init() { -#if TFT_USE_FRAMEBUFFER - static c_surface surface(TFT_WIDTH, TFT_HEIGHT, 2, Z_ORDER_LEVEL_0); - static c_display display(_framebuffer, TFT_WIDTH, TFT_HEIGHT, &surface); - psurface_guilite = &surface; - pdisplay_guilite = &display; -#else - static c_surface_no_fb surface(TFT_WIDTH, TFT_HEIGHT, 2, &my_gfx_op, Z_ORDER_LEVEL_0); - static c_display display(NULL, TFT_WIDTH, TFT_HEIGHT, &surface); + //Always draw into a 320x240 Framebuffer on stm32 + static c_surface_no_fb surface(320, 240, 2, &my_gfx_op, Z_ORDER_LEVEL_0); + static c_display display(NULL, 320, 240, &surface); + scale = MIN(TFT_HEIGHT / 240.0f, TFT_WIDTH / 320.0f); my_gfx_op.draw_pixel = _draw_pixel; my_gfx_op.fill_rect = _fill_rect; -#endif psurface_guilite = &surface; pdisplay_guilite = &display; register_debug_function(_tft_assert, _tft_log_out); diff --git a/src/port_stm32f7/stm37f750-dk/port_conf.h b/src/port_stm32f7/stm37f750-dk/port_conf.h index 985cb98b..d3495da1 100644 --- a/src/port_stm32f7/stm37f750-dk/port_conf.h +++ b/src/port_stm32f7/stm37f750-dk/port_conf.h @@ -55,8 +55,10 @@ typedef enum { #define ENABLE_TFT_DISPLAY 1 #define TFT_WIDTH 480 #define TFT_HEIGHT 272 +//Want one of these dimensions to be to a multiple of above +#define TFT_FRAMEBUFFER_WIDTH 362 +#define TFT_FRAMEBUFFER_HEIGHT 272 #define TFT_PIXEL_SIZE 4 -#define TFT_USE_FRAMEBUFFER 0 /* Define for variables to store in flash only */ #ifndef PROGMEM diff --git a/src/port_stm32f7/stm37f769-dk/port_conf.h b/src/port_stm32f7/stm37f769-dk/port_conf.h index cca7065b..ca2316a0 100644 --- a/src/port_stm32f7/stm37f769-dk/port_conf.h +++ b/src/port_stm32f7/stm37f769-dk/port_conf.h @@ -55,8 +55,9 @@ typedef enum { #define ENABLE_TFT_DISPLAY 1 #define TFT_WIDTH 800 #define TFT_HEIGHT 472 +#define TFT_FRAMEBUFFER_WIDTH 320 +#define TFT_FRAMEBUFFER_HEIGHT 236 #define TFT_PIXEL_SIZE 4 -#define TFT_USE_FRAMEBUFFER 0 /* Define for variables to store in flash only */ #ifndef PROGMEM diff --git a/src/port_teensy41/port_conf.h b/src/port_teensy41/port_conf.h index 73b146fc..4888b398 100644 --- a/src/port_teensy41/port_conf.h +++ b/src/port_teensy41/port_conf.h @@ -44,11 +44,12 @@ typedef enum { /* TFT DISPLAY */ #define ENABLE_TFT_DISPLAY 1 -#define TFT_ROTATION 1 //0-3 #define TFT_WIDTH 320 #define TFT_HEIGHT 240 +#define TFT_FRAMEBUFFER_WIDTH 320 +#define TFT_FRAMEBUFFER_HEIGHT 240 #define TFT_PIXEL_SIZE 2 -#define TFT_USE_FRAMEBUFFER 1 +#define TFT_ROTATION 1 //0-3 /* Define for variables to store in flash only */ #ifndef PROGMEM diff --git a/src/port_template/port_conf.h b/src/port_template/port_conf.h index 7f6f4e44..4bdb93e3 100644 --- a/src/port_template/port_conf.h +++ b/src/port_template/port_conf.h @@ -1,37 +1,41 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT -#ifndef _USB64_CONF_h -#define _USB64_CONF_h - -/* PIN MAPPING - Teensy uses an Arduino Backend, we just assign the enum to the Arduino Pin number - USB64_PIN_MAX must be the largest pin number in the list add one*/ -typedef enum { - USER_LED_PIN, - N64_FRAME_PIN, - HW_RUMBLE, - N64_CONSOLE_SENSE_PIN, - N64_CONTROLLER_1_PIN, - N64_CONTROLLER_2_PIN, - N64_CONTROLLER_3_PIN, - N64_CONTROLLER_4_PIN, - USB64_PIN_MAX, -} usb64_pin_t; - -/* TFT DISPLAY */ -#define ENABLE_TFT_DISPLAY 1 -#define TFT_ROTATION 1 //0-3 -#define TFT_WIDTH 320 -#define TFT_HEIGHT 240 -#define TFT_PIXEL_SIZE 2 -#define TFT_USE_FRAMEBUFFER 1 - -/* Optional, to save RAM, define for variables to store in flash only */ -#ifndef PROGMEM -#define PROGMEM -#endif -/* Optional, to save RAM, define for function to store in flash only */ -#ifndef FLASHMEM -#define FLASHMEM -#endif - -#endif +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT +#ifndef _USB64_CONF_h +#define _USB64_CONF_h + +/* PIN MAPPING - Teensy uses an Arduino Backend, we just assign the enum to the Arduino Pin number + USB64_PIN_MAX must be the largest pin number in the list add one*/ +typedef enum { + USER_LED_PIN, + N64_FRAME_PIN, + HW_RUMBLE, + N64_CONSOLE_SENSE_PIN, + N64_CONTROLLER_1_PIN, + N64_CONTROLLER_2_PIN, + N64_CONTROLLER_3_PIN, + N64_CONTROLLER_4_PIN, + USB64_PIN_MAX, +} usb64_pin_t; + +/* TFT DISPLAY */ +#define ENABLE_TFT_DISPLAY 1 +//Draw to a framebuffer, which you can then send to a screen (via DMA etc) +#define TFT_USE_FRAMEBUFFER 0 +#define TFT_WIDTH 320 +#define TFT_HEIGHT 240 +//The TFT image is drawn within the framebuffer size. You can have this differ from above +//if you dont want to draw into the entire screen space. +#define TFT_FRAMEBUFFER_WIDTH 320 +#define TFT_FRAMEBUFFER_HEIGHT 240 +#define TFT_PIXEL_SIZE 2 //16bpp = 2, 32bpp = 4 + +/* Optional, to save RAM, define for variables to store in flash only */ +#ifndef PROGMEM +#define PROGMEM +#endif +/* Optional, to save RAM, define for function to store in flash only */ +#ifndef FLASHMEM +#define FLASHMEM +#endif + +#endif diff --git a/src/tft.cpp b/src/tft.cpp index 56637be0..3c22078d 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -14,6 +14,8 @@ #include "controller_icon.h" #include "usb64_logo.h" +static const int WIDTH = TFT_FRAMEBUFFER_WIDTH; +static const int HEIGHT = TFT_FRAMEBUFFER_HEIGHT; static uint8_t _tft_page = 0; static uint8_t _tft_page_changed = 1; static uint8_t _tft_max_pages = 2; @@ -93,7 +95,7 @@ FLASHMEM void tft_init() return; } - psurface_guilite->fill_rect(0, 0, TFT_WIDTH, TFT_HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); + psurface_guilite->fill_rect(0, 0, WIDTH, HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); static c_image usb64_image; memset(&usb64_image, 0, sizeof(c_image)); @@ -125,7 +127,7 @@ void tft_try_update() //ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb565le -s 320x240 -i tft_dump.bin -f image2 -vcodec png tft_dump.png if (n64hal_millis() > 10000) { - fileio_write_to_file("tft_dump.bin", (uint8_t *)tft_dev_get_fb(), TFT_WIDTH * TFT_HEIGHT * 2); + fileio_write_to_file("tft_dump.bin", (uint8_t *)tft_dev_get_fb(), WIDTH * HEIGHT * 2); debug_print_status("TFT framebuffer dumped\n"); while (1) yield(); } @@ -159,7 +161,7 @@ void tft_force_update() _tft_page_changed = 0; if (_tft_page == 0) { - psurface_guilite->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); + psurface_guilite->fill_rect(0, 40, WIDTH, HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); static c_image controller_image; BITMAP_INFO _image; memset(&controller_image, 0, sizeof(c_image)); @@ -167,14 +169,14 @@ void tft_force_update() _image.height = 45; _image.width = 48; _image.pixel_color_array = controller_icon; - controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 0 / 4), TFT_BG_COLOR); - controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 1 / 4), TFT_BG_COLOR); - controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 2 / 4), TFT_BG_COLOR); - controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((TFT_HEIGHT - 45) * 3 / 4), TFT_BG_COLOR); + controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((HEIGHT - 45) * 0 / 4), TFT_BG_COLOR); + controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((HEIGHT - 45) * 1 / 4), TFT_BG_COLOR); + controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((HEIGHT - 45) * 2 / 4), TFT_BG_COLOR); + controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((HEIGHT - 45) * 3 / 4), TFT_BG_COLOR); } else if (_tft_page == 1) { - psurface_guilite->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); + psurface_guilite->fill_rect(0, 40, WIDTH, HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); } } @@ -188,7 +190,7 @@ void tft_force_update() controller_status[i].set_surface(psurface_guilite); controller_status[i].set_bg_color(TFT_BG_COLOR); controller_status[i].set_font_color(colour); - controller_status[i].set_wnd_pos(50, (45 + 0) + ((TFT_HEIGHT - 45) * i / 4), TFT_WIDTH, Arial_19_GL.height); + controller_status[i].set_wnd_pos(50, (45 + 0) + ((HEIGHT - 45) * i / 4), WIDTH, Arial_19_GL.height); controller_status[i].set_font_type(&Arial_19_GL); controller_status[i].set_str(n64_peri_to_string(&n64_in_dev[i])); controller_status[i].show_window(); @@ -197,7 +199,7 @@ void tft_force_update() controller_id[i].set_surface(psurface_guilite); controller_id[i].set_font_color(colour); controller_id[i].set_bg_color(TFT_BG_COLOR); - controller_id[i].set_wnd_pos(50, (45 + 20) + ((TFT_HEIGHT - 45) * i / 4), TFT_WIDTH, Arial_19_GL.height); + controller_id[i].set_wnd_pos(50, (45 + 20) + ((HEIGHT - 45) * i / 4), WIDTH, Arial_19_GL.height); controller_id[i].set_font_type(&Arial_19_GL); controller_id[i].set_str(text_buff); controller_id[i].show_window(); @@ -205,7 +207,7 @@ void tft_force_update() } else if (_tft_page == 1) { - psurface_guilite->fill_rect(0, 40, TFT_WIDTH, TFT_HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); + psurface_guilite->fill_rect(0, 40, WIDTH, HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); for (int i = 0; i < _tft_log_max_lines; i++) { if (_tft_log_text_lines[i] == NULL) @@ -214,7 +216,7 @@ void tft_force_update() tft_log[i].set_surface(psurface_guilite); tft_log[i].set_bg_color(TFT_BG_COLOR); tft_log[i].set_font_color(GL_RGB(255, 255, 255)); - tft_log[i].set_wnd_pos(0, 45 + i * Arial_14_GL.height, TFT_WIDTH, Arial_14_GL.height); + tft_log[i].set_wnd_pos(0, 45 + i * Arial_14_GL.height, WIDTH, Arial_14_GL.height); tft_log[i].set_font_type(&Arial_14_GL); tft_log[i].set_str(_tft_log_text_lines[i]); tft_log[i].show_window(); @@ -237,7 +239,7 @@ void tft_force_update() n64_status.set_surface(psurface_guilite); n64_status.set_bg_color(TFT_BG_COLOR); n64_status.set_font_color(colour); - n64_status.set_wnd_pos(TFT_WIDTH - (10 * 8), 0, 100, Arial_14_GL.height); + n64_status.set_wnd_pos(WIDTH - (10 * 8), 0, 100, Arial_14_GL.height); n64_status.set_font_type(&Arial_14_GL); n64_status.set_str(n64_status_text); n64_status.show_window(); From bd3faf45bf4e1d892847a9d225afbf49556489b0 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Wed, 26 Jan 2022 21:50:17 +0000 Subject: [PATCH 116/121] STM32FXX: Add builds to CI --- .github/workflows/build.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9a1d4c0d..1cb401b3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - board: [teensy41,template] + board: [teensy41,disco_f769ni,disco_f750n8,template] steps: - name: Checkout repo @@ -52,15 +52,16 @@ jobs: platformio run -e ${{ matrix.board }} # platformio system prune --force - - name: Upload firmware artifact to current run + - if: matrix.board != 'template' + name: Upload firmware artifact to current run uses: actions/upload-artifact@v2 with: name: test-firmware-${{ matrix.board }} path: | .pio/build/**/*.hex - .pio/build/**/*.bin + # .pio/build/**/*.bin # Should not be required for any boards, and makes upload file size incorrect! .pio/build/**/*.elf - .pio/build/**/*.map + # .pio/build/**/*.map # Currently not generated. - if: github.event_name == 'push' && github.ref == 'refs/heads/master' #TODO handle previews name: Create Release @@ -72,7 +73,7 @@ jobs: draft: false prerelease: false - - if: github.event_name == 'push' && github.ref == 'refs/heads/master' #TODO handle previews + - if: github.event_name == 'push' && github.ref == 'refs/heads/master' && matrix.board != 'template' #TODO handle previews name: Upload binary for release id: upload-release-asset uses: actions/upload-release-asset@v1 From a627e9b3bb3ffe8391cf9f1ade98b06513a48b76 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Thu, 27 Jan 2022 05:29:07 +0000 Subject: [PATCH 117/121] N64 :Refactor mempak title to cpak --- README.md | 12 +++---- USAGE.md | 22 ++++++------- src/common.h | 2 +- src/main.cpp | 69 ++++++++++++++++++++-------------------- src/n64/n64_controller.c | 30 ++++++++--------- src/n64/n64_controller.h | 14 ++++---- src/n64/n64_mempak.c | 12 +++---- src/n64/n64_mempak.h | 8 ++--- src/n64/n64_virtualpak.c | 14 ++++---- src/n64/n64_virtualpak.h | 4 +-- src/tft.cpp | 12 +++---- 11 files changed, 100 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index 2577f6a6..134d18e7 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,14 @@ Precompiled binaries can be downloaded from [Releases](https://github.com/Ryzee1 **NOTE: This project is still in development, PRs and ideas are welcome. See todo list for ideas.** - [x] N64 controller emulation (up to four controllers at once!). -- [x] Rumblepak emulation. -- [x] Mempak emulation with four selectable banks. Technically unlimited. -- [x] Transferpak emulation. Put Gameboy ROMS on an SD Card! +- [x] Rumble Pak emulation. +- [x] Controller Pak emulation with four selectable banks. Technically unlimited. +- [x] Transfer Pak emulation. Put Gameboy ROMS on an SD Card! - [x] N64 mouse emulation. Use a USB Mouse! - [x] N64 Randnet emulation. Use a USB keyboard! - [x] Configurable deadzones and sensitivity from the N64 Console. - [x] True dual analog sticks with GoldenEye and Perfect Dark. -- [x] SD card driver with FATFS support for storage/backup of Gameboy ROMS, mempaks etc. +- [x] SD card driver with FATFS support for storage/backup of Gameboy ROMS, controller paks etc. - [x] A single hardwired controller interface for ultimate hacking. - [x] Optional TFT LCD Support. @@ -36,10 +36,10 @@ Precompiled binaries can be downloaded from [Releases](https://github.com/Ryzee1 - A hardwired controller, use your own buttons etc. ## Controls -- Back + D-Pad = Insert Mempak banks 1 to 4 +- Back + D-Pad = Insert Controller Pak banks 0 to 3 - Back + LB = Insert Rumblepak - Back + RB = Insert Transferpak -- Back + Start = Select *virtual pak* (Use in-game mempak managers to configure the device) +- Back + Start = Select *virtual pak* (Use in-game Controller Pak managers to configure the device) - Back + B = Switch to true dual-analog stick more for GoldenEye 007/Perfect Dark - Back + A = Backup buffered memory to SD Card **(DO THIS BEFORE POWER OFF!)** diff --git a/USAGE.md b/USAGE.md index d819e2f4..2ee72242 100644 --- a/USAGE.md +++ b/USAGE.md @@ -1,24 +1,24 @@ # Usage -* [Mempaks](#mempaks) -* [Rumblepaks](#rumblepaks) -* [Transferpaks](#transferpaks) -* [Virtualpak](#virtualpak) +* [Controller Paks](#controller-paks) +* [Rumble Paks](#rumble-paks) +* [Transfer Paks](#transfer-paks) +* [Virtual Pak](#virtual-pak) * [Dual Stick Mode](#dual-stick-mode) * [N64 Mouse](#n64-mouse) * [TFT LCD Display](#tft-lcd-display) * [Debug](#debug) -## Mempaks +## Controller Paks * usb64 can simulate four Mempaks simultaneously. To select a Mempak press `BACK+D-PAD` direction to select the respective bank. * Two controllers cannot have the same bank selected. The second controller will revert to a Rumblepak. * Do not unplug the usb64's power before turning off the n64 console to prevent data loss. The usb64 senses the n64 console turning off and flushes data to the SD Card. * Inserting the SD card into your PC will show Mempaks as `MEMPAKXX.MPK` where XX is the bank number. You can back these up to your PC. -## Rumblepaks +## Rumble Paks * usb64 can simulate four Rumblepaks simultaneously. Rumblepaks are the default peripheral on power up. To select a Rumblepak press `BACK+LB`. * The usb controller must support force feedback. -## Transferpaks +## Transfer Paks * usb64 can simulate four transferpaks simulateneously. The select a Transferpak press `BACK+RB`. The transferpak will attempt to load the previously set Gameboy or Gameboy Colour ROM from the SD Card. * To select the ROM to load, you must first use the [*VirtualPak*](#virtualpak). If a ROM isn't selected, or fails to load, it will revert to a Rumblepak. * Avoid having two controllers access the same ROM at once. @@ -26,11 +26,11 @@ * Gameboy saves can be copied over to the SD Card for use with the Transferpak. The file name must match the ROM save with a `.SAV` extension. * You can simulate four transferpaks, with four difference ROMS, with four different save files!

tpak_6 tpak_7

silver tpak_1

tpak_5 tpak_8

-## Virtualpak -* The Virtualpak is one of my favourite features. It's like a Mempak, but is not used for save files. It exploits the Mempak managers built into some N64 games to configure the usb64 device! +## Virtual Pak +* The VirtualCpak is one of my favourite features. It's like a Controller Pak, but is not used for save files. It exploits the Mempak managers built into some N64 games to configure the usb64 device! * To select the Virtualpak press `BACK+START`. -* To use the Virtualpak, boot into a game that has a Mempak manager. Some games will work better than others. `Army Men: Air Combat` is a good one. `Perfect Dark` works well too. Hold START whilst the game is booting to access the Mempak manager. The follow screens show `Army Men: Air Combat` and `Perfect Dark` as an example.

vp_main vp_perfectdark

-* To select an item, you actually delete that note from the Mempak. usb64 detects what row you selected as if navigating a menu! +* To use the Virtualpak, boot into a game that has a Contrroller Pak manager. Some games will work better than others. `Army Men: Air Combat` is a good one. `Perfect Dark` works well too. Hold START whilst the game is booting to access the Controller Pak manager. The follow screens show `Army Men: Air Combat` and `Perfect Dark` as an example.

vp_main vp_perfectdark

+* To select an item, you actually delete that note from the Controller Pak. usb64 detects what row you selected as if navigating a menu! * **TPAK SETTINGS** is used to configure what ROM to load into the Transferpak. This will scan the SD card for files with `.gb` and `.gbc` extensions. A `*` will print next to the currently set ROM. You can have up to ten ROMs on the SD card. After this they will just get ignored.

vp_tpak

* **CONT SETTINGS** is used to configure the controller. You can change deadzone, Sensitivity, toggle on/off snapping to 45deg angles and toggle on/off a octagonal N64 stick correction. The set values is shown as a number next to the row. Each controller can be configured individually. Note: Some controllers will have deadzones or 45 degree angle snapping built in. For these, usb64 can't disable it.

vp_cont

* **USB64 INFO1** shows what controller is connected to that port.

vp_info1

diff --git a/src/common.h b/src/common.h index bc422c9d..a62ac93b 100644 --- a/src/common.h +++ b/src/common.h @@ -49,7 +49,7 @@ extern "C" { #define MAX_FILENAME_LEN 256 #define SETTINGS_FILENAME "SETTINGS.DAT" #define GAMEBOY_SAVE_EXT ".SAV" //ROMFILENAME.SAV -#define MEMPAK_SAVE_EXT ".MPK" //MEMPAKXX.MPK +#define CPAK_SAVE_EXT ".MPK" //CONTROLLER_PAK_XX.MPK /* FIRMWARE DEFAULTS (CONFIGURABLE DURING USE) */ #define DEFAULT_SENSITIVITY 2 //0 to 4 (0 = low sensitivity, 4 = max) diff --git a/src/main.cpp b/src/main.cpp index 3407074f..6098e4ee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -281,10 +281,10 @@ void loop() timer_peri_change[c] = n64hal_millis(); /* CLEAR CURRENT PERIPHERALS */ - if (n64_in_dev[c].mempack != NULL) + if (n64_in_dev[c].cpak != NULL) { - n64_in_dev[c].mempack->data = NULL; - n64_in_dev[c].mempack->id = VIRTUAL_PAK; + n64_in_dev[c].cpak->data = NULL; + n64_in_dev[c].cpak->id = VIRTUAL_PAK; } if (n64_in_dev[c].tpak != NULL) @@ -317,7 +317,7 @@ void loop() //Changing peripheral to RUMBLEPAK if (n64_buttons & N64_LB) { - n64_in_dev[c].next_peripheral = PERI_RUMBLE; + n64_in_dev[c].next_peripheral = PERI_RPAK; debug_print_status("[MAIN] C%u to rpak\n", c); } @@ -353,7 +353,7 @@ void loop() if (gb_cart->rom == NULL || (gb_cart->ram == NULL && gb_cart->ramsize > 0)) { - n64_in_dev[c].next_peripheral = PERI_RUMBLE; //Error, just set to rumblepak + n64_in_dev[c].next_peripheral = PERI_RPAK; //Error, just set to rumblepak debug_print_error("[MAIN] ERROR: Could not allocate rom or ram buffer for %s\n", n64_in_dev[c].tpak->gbcart->filename); n64_in_dev[c].tpak->gbcart->romsize = 0; n64_in_dev[c].tpak->gbcart->ramsize = 0; @@ -363,7 +363,7 @@ void loop() } else { - n64_in_dev[c].next_peripheral = PERI_RUMBLE; //Error, just set to rumblepak + n64_in_dev[c].next_peripheral = PERI_RPAK; //Error, just set to rumblepak if (gb_cart->filename[0] == '\0') debug_print_error("[MAIN] ERROR: No default TPAK ROM set or no ROMs found\n"); else if (memory_get_ext_ram_size() == 0) @@ -373,58 +373,59 @@ void loop() } } - //Changing peripheral to MEMPAK + //Changing peripheral to CPAK if ((n64_buttons & N64_DU || n64_buttons & N64_DD || n64_buttons & N64_DL || n64_buttons & N64_DR || n64_buttons & N64_ST)) { - n64_in_dev[c].next_peripheral = PERI_MEMPAK; + n64_in_dev[c].next_peripheral = PERI_CPAK; - //Allocate mempack based on combo if available - uint32_t mempak_bank = 0; + //Allocate cpak based on combo if available + uint32_t cpak_bank_num = 0; uint16_t b = n64_buttons; - (b & N64_DU) ? mempak_bank = 0 : (0); - (b & N64_DR) ? mempak_bank = 1 : (0); - (b & N64_DD) ? mempak_bank = 2 : (0); - (b & N64_DL) ? mempak_bank = 3 : (0); - (b & N64_ST) ? mempak_bank = VIRTUAL_PAK : (0); + (b & N64_DU) ? cpak_bank_num = 0 : (0); + (b & N64_DR) ? cpak_bank_num = 1 : (0); + (b & N64_DD) ? cpak_bank_num = 2 : (0); + (b & N64_DL) ? cpak_bank_num = 3 : (0); + (b & N64_ST) ? cpak_bank_num = VIRTUAL_PAK : (0); //Create the filename char filename[32]; - snprintf(filename, sizeof(filename), "MEMPAK%02u%s", (unsigned int)mempak_bank, MEMPAK_SAVE_EXT); + snprintf(filename, sizeof(filename), "CONTROLLER_PAK_%02u%s", (unsigned int)cpak_bank_num, CPAK_SAVE_EXT); - //Scan controllers to see if mempack is in use + //Scan controllers to see if cpak is in use for (uint32_t i = 0; i < MAX_CONTROLLERS; i++) { - if (n64_in_dev[i].mempack->id == mempak_bank && mempak_bank != VIRTUAL_PAK) + if (n64_in_dev[i].cpak->id == cpak_bank_num && cpak_bank_num != VIRTUAL_PAK) { - debug_print_status("[MAIN] WARNING: mpak in use by C%u. Setting to rpak\n", i); - n64_in_dev[c].next_peripheral = PERI_RUMBLE; + debug_print_status("[MAIN] WARNING: cpak in use by C%u. Setting to rpak\n", i); + n64_in_dev[c].next_peripheral = PERI_RPAK; break; } } - //Mempack wasn't in use, so allocate it in ram - if (n64_in_dev[c].next_peripheral != PERI_RUMBLE && mempak_bank != VIRTUAL_PAK) + //cpak wasn't in use, so allocate it in ram + if (n64_in_dev[c].next_peripheral != PERI_RPAK && cpak_bank_num != VIRTUAL_PAK) { - n64_in_dev[c].mempack->data = memory_alloc_ram(filename, MEMPAK_SIZE, MEMORY_READ_WRITE); + n64_in_dev[c].cpak->data = memory_alloc_ram(filename, CPAK_SIZE, MEMORY_READ_WRITE); + //TODO: create an initalized CPAK data if file is empty or does not exist?! } - if (n64_in_dev[c].mempack->data != NULL) + if (n64_in_dev[c].cpak->data != NULL) { - debug_print_status("[MAIN] C%u to mpak %u\n", c, mempak_bank); - n64_in_dev[c].mempack->virtual_is_active = 0; - n64_in_dev[c].mempack->id = mempak_bank; + debug_print_status("[MAIN] C%u to cpak %u\n", c, cpak_bank_num); + n64_in_dev[c].cpak->virtual_is_active = 0; + n64_in_dev[c].cpak->id = cpak_bank_num; } - else if (mempak_bank == VIRTUAL_PAK) + else if (cpak_bank_num == VIRTUAL_PAK) { - debug_print_status("[MAIN] C%u to virtual pak\n", c); - n64_virtualpak_init(n64_in_dev[c].mempack); + debug_print_status("[MAIN] C%u to virtual cpak\n", c); + n64_virtualpak_init(n64_in_dev[c].cpak); } else { debug_print_error("[MAIN] ERROR: Could not alloc RAM for %s, setting to rpak\n", filename); - n64_in_dev[c].next_peripheral = PERI_RUMBLE; + n64_in_dev[c].next_peripheral = PERI_RPAK; } } } @@ -438,11 +439,11 @@ void loop() } //Update the virtual pak if required - if (n64_in_dev[c].mempack->virtual_update_req == 1) + if (n64_in_dev[c].cpak->virtual_update_req == 1) { //For the USB64-INFO1 Page, I write the controller info (PID,VID etc) char msg[256]; - n64_virtualpak_update(n64_in_dev[c].mempack); //Update so we get the right page + n64_virtualpak_update(n64_in_dev[c].cpak); //Update so we get the right page uint8_t c_page = n64_virtualpak_get_controller_page(); sprintf(msg, "%u:0x%04x/0x%04x\n%.15s\n%.15s\n", c_page + 1, @@ -453,7 +454,7 @@ void loop() n64_virtualpak_write_info_1(msg); //Normal update - n64_virtualpak_update(n64_in_dev[c].mempack); + n64_virtualpak_update(n64_in_dev[c].cpak); } } //END FOR LOOP diff --git a/src/n64/n64_controller.c b/src/n64/n64_controller.c index 0a51b0d8..09056852 100644 --- a/src/n64/n64_controller.c +++ b/src/n64/n64_controller.c @@ -9,7 +9,7 @@ //#define USE_N64_ADDRESS_CRC n64_rumblepak n64_rpak[MAX_CONTROLLERS]; -n64_mempack n64_mpack[MAX_CONTROLLERS]; +n64_controllerpak n64_cpak[MAX_CONTROLLERS]; n64_transferpak n64_tpak[MAX_CONTROLLERS]; gameboycart gb_cart[MAX_CONTROLLERS]; @@ -57,12 +57,12 @@ void n64_subsystem_init(n64_input_dev_t *in_dev) in_dev[i].id = i; in_dev[i].current_bit = 7; in_dev[i].current_byte = 0; - in_dev[i].current_peripheral = PERI_RUMBLE; + in_dev[i].current_peripheral = PERI_RPAK; in_dev[i].next_peripheral = in_dev[i].current_peripheral; in_dev[i].rpak = &n64_rpak[i]; - in_dev[i].mempack = &n64_mpack[i]; - in_dev[i].mempack->id = VIRTUAL_PAK; - in_dev[i].mempack->data = NULL; + in_dev[i].cpak = &n64_cpak[i]; + in_dev[i].cpak->id = VIRTUAL_PAK; + in_dev[i].cpak->data = NULL; in_dev[i].tpak = &n64_tpak[i]; in_dev[i].tpak->gbcart = &gb_cart[i]; in_dev[i].interrupt_attached = false; @@ -341,7 +341,7 @@ void n64_controller_hande_new_edge(n64_input_dev_t *cont) { case 0x0: //VIRTUAL MEMPAK NOTE TABLE HOOK - if (cont->mempack->virtual_is_active && cont->current_peripheral == PERI_MEMPAK && + if (cont->cpak->virtual_is_active && cont->current_peripheral == PERI_CPAK && peri_address >= 0x300 && peri_address < 0x500) { /* @@ -352,8 +352,8 @@ void n64_controller_hande_new_edge(n64_input_dev_t *cont) * I use this as a hacky menu for the N64 */ uint32_t row = (peri_address - 0x300) / 0x20; //What row you have 'selected' 0-15 - cont->mempack->virtual_update_req = 1; - cont->mempack->virtual_selected_row = row; + cont->cpak->virtual_update_req = 1; + cont->cpak->virtual_selected_row = row; debug_print_n64("[N64] Virtualpak write at row %u\n", row); break; } @@ -365,8 +365,8 @@ void n64_controller_hande_new_edge(n64_input_dev_t *cont) case 0x5: case 0x6: case 0x7: - if (cont->current_peripheral == PERI_MEMPAK && !cont->crc_error) - n64_mempack_write32(cont->mempack, peri_address, &cont->data_buffer[N64_DATA_POS]); + if (cont->current_peripheral == PERI_CPAK && !cont->crc_error) + n64_cpak_write32(cont->cpak, peri_address, &cont->data_buffer[N64_DATA_POS]); break; case 0x8: if (cont->current_peripheral == PERI_TPAK) @@ -376,7 +376,7 @@ void n64_controller_hande_new_edge(n64_input_dev_t *cont) (cont->data_buffer[N64_DATA_POS] == 0xFE) ? tpak_reset(cont->tpak) : (0); debug_print_tpak("[TPAK] Powerstate set to %u\n", cont->tpak->power_state); } - else if (cont->current_peripheral == PERI_RUMBLE) + else if (cont->current_peripheral == PERI_RPAK) { //N64 writes 32 bytes of 0x80 to initialise the rumblepak, 0xFE to reset it (cont->data_buffer[N64_DATA_POS] == 0x80) ? cont->rpak->initialised = 1 : (0); @@ -401,7 +401,7 @@ void n64_controller_hande_new_edge(n64_input_dev_t *cont) } break; case 0xC: - if (cont->current_peripheral == PERI_RUMBLE) + if (cont->current_peripheral == PERI_RPAK) { (cont->data_buffer[N64_DATA_POS] == 0x01) ? (cont->rpak->state = RUMBLE_START) : (cont->rpak->state = RUMBLE_STOP); @@ -483,15 +483,15 @@ void n64_controller_hande_new_edge(n64_input_dev_t *cont) case 0x5: case 0x6: case 0x7: - if (cont->current_peripheral == PERI_MEMPAK) + if (cont->current_peripheral == PERI_CPAK) { - n64_mempack_read32(cont->mempack, peri_address, &cont->data_buffer[N64_DATA_POS]); + n64_cpak_read32(cont->cpak, peri_address, &cont->data_buffer[N64_DATA_POS]); } break; case 0x8: case 0x9: //If rumblepak is initialised, respond with 32bytes of 0x80. - if (cont->current_peripheral == PERI_RUMBLE && cont->rpak->initialised == 1) + if (cont->current_peripheral == PERI_RPAK && cont->rpak->initialised == 1) { memset(&cont->data_buffer[N64_DATA_POS], 0x80, 32); debug_print_n64("[N64] Request rumblepak state. Sending 0x80s (its initialised)\n"); diff --git a/src/n64/n64_controller.h b/src/n64/n64_controller.h index f6c45c62..bab4432c 100644 --- a/src/n64/n64_controller.h +++ b/src/n64/n64_controller.h @@ -39,8 +39,8 @@ typedef enum typedef enum { PERI_NONE, - PERI_RUMBLE, - PERI_MEMPAK, + PERI_RPAK, + PERI_CPAK, PERI_TPAK } n64_peri_type; @@ -55,11 +55,11 @@ typedef struct n64_input_type type; //Store the type of input device. Controller, Mouse. Randnet etc. n64_buttonmap b_state; //N64 controller button and analog stick map n64_randnet_kb kb_state; //Randnet keyboard object - n64_peri_type current_peripheral; //Peripheral flag, PERI_NONE, PERI_RUMBLE, PERI_MEMPAK, PERI_TPAK + n64_peri_type current_peripheral; //Peripheral flag, PERI_NONE, PERI_RPAK, PERI_CPAK, PERI_TPAK n64_peri_type next_peripheral; //What Peripheral to change to next after timer n64_transferpak *tpak; //Pointer to installed transferpak n64_rumblepak *rpak; //Pointer to installed rumblepak - n64_mempack *mempack; //Pointer to installed mempack + n64_controllerpak *cpak; //Pointer to installed controllerpak // uint32_t interrupt_attached; //Flag is set when this controller is connected to an ext int. uint32_t bus_idle_timer_clks; //Timer counter for bus idle timing @@ -126,9 +126,9 @@ typedef struct #define RANDNET_FLAG_EXCESS_BUTTONS (1 << 4) //Mempak -#define MEMPAK_SIZE 32768 -#define MAX_MEMPAKS MAX_CONTROLLERS -#define VIRTUAL_PAK MAX_MEMPAKS +#define CPAK_SIZE 32768 +#define MAX_CPAKS MAX_CONTROLLERS +#define VIRTUAL_PAK MAX_CPAKS void n64_subsystem_init(n64_input_dev_t *in_dev); void n64_controller_hande_new_edge(n64_input_dev_t *cont); diff --git a/src/n64/n64_mempak.c b/src/n64/n64_mempak.c index 60c8af44..43ced3fe 100644 --- a/src/n64/n64_mempak.c +++ b/src/n64/n64_mempak.c @@ -3,26 +3,26 @@ #include "n64_controller.h" -void n64_mempack_read32(n64_mempack *mempack, uint16_t address, uint8_t *rx_buff) +void n64_cpak_read32(n64_controllerpak *cpak, uint16_t address, uint8_t *rx_buff) { - if (mempack->virtual_is_active) + if (cpak->virtual_is_active) { n64_virtualpak_read32(address, rx_buff); } else { - n64hal_read_extram(rx_buff, mempack->data, address, 32); + n64hal_read_extram(rx_buff, cpak->data, address, 32); } } -void n64_mempack_write32(n64_mempack *mempack, uint16_t address, uint8_t *tx_buff) +void n64_cpak_write32(n64_controllerpak *cpak, uint16_t address, uint8_t *tx_buff) { - if (mempack->virtual_is_active) + if (cpak->virtual_is_active) { n64_virtualpak_write32(address, tx_buff); } else { - n64hal_write_extram(tx_buff, mempack->data, address, 32); + n64hal_write_extram(tx_buff, cpak->data, address, 32); } } diff --git a/src/n64/n64_mempak.h b/src/n64/n64_mempak.h index 82188069..ffc5f83d 100644 --- a/src/n64/n64_mempak.h +++ b/src/n64/n64_mempak.h @@ -8,7 +8,7 @@ extern "C" { #endif -#define MEMPAK_SIZE 32768 +#define CPAK_SIZE 32768 typedef struct { @@ -18,10 +18,10 @@ typedef struct uint32_t virtual_is_active; uint32_t virtual_update_req; uint32_t virtual_selected_row; -} n64_mempack; +} n64_controllerpak; -void n64_mempack_read32(n64_mempack *mempack, uint16_t address, uint8_t *rx_buff); -void n64_mempack_write32(n64_mempack *mempack, uint16_t address, uint8_t *tx_buff); +void n64_cpak_read32(n64_controllerpak *cpak, uint16_t address, uint8_t *rx_buff); +void n64_cpak_write32(n64_controllerpak *cpak, uint16_t address, uint8_t *tx_buff); #ifdef __cplusplus } diff --git a/src/n64/n64_virtualpak.c b/src/n64/n64_virtualpak.c index b45a75d0..d1403bed 100644 --- a/src/n64/n64_virtualpak.c +++ b/src/n64/n64_virtualpak.c @@ -30,7 +30,7 @@ uint8_t n64_virtualpak_scratch[0x20] = { 0x81, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}; -//First 0x300 bytes of mempak. I took this from a mempak I generated on my n64. +//First 0x300 bytes of controller pak. I took this from a controller pak I generated on my n64. //const as the console only needs to read from this area const uint8_t n64_virtualpak_header[0x300] PROGMEM = { 0x81, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, @@ -82,7 +82,7 @@ const uint8_t n64_virtualpak_header[0x300] PROGMEM = { 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03}; -//This is the notesTable located at address 0x300 to 0x500 in the mempack address space. +//This is the notesTable located at address 0x300 to 0x500 in the cpak address space. //This initialises the title blocks as all blank titles using 1 page each. //Basically what is displayed on the mempak manager page. /* 0x4E = N (Media Type Cartridge) @@ -142,7 +142,7 @@ uint8_t n64_virtualpak_note_table[0x200] = { static void n64_virtualpak_write_string(char *msg, uint8_t line, uint8_t ext) { //Obtained from pulling known save titles and a bit of trial and error - static const uint8_t MEMPACK_CHARMAP[] = + static const uint8_t CPAK_CHARMAP[] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', @@ -173,9 +173,9 @@ static void n64_virtualpak_write_string(char *msg, uint8_t line, uint8_t ext) msg[i] = '-'; //replace _ with - //Find a match in the CHARMAP - for (uint32_t j = 0; j < sizeof(MEMPACK_CHARMAP); j++) + for (uint32_t j = 0; j < sizeof(CPAK_CHARMAP); j++) { - if (msg[i] == MEMPACK_CHARMAP[j]) + if (msg[i] == CPAK_CHARMAP[j]) n64char = j; } @@ -195,7 +195,7 @@ static void n64_virtualpak_write_string(char *msg, uint8_t line, uint8_t ext) } } -void n64_virtualpak_init(n64_mempack *vpak) +void n64_virtualpak_init(n64_controllerpak *vpak) { vpak->virtual_is_active = 1; vpak->virtual_selected_row = MENU_MAIN; @@ -252,7 +252,7 @@ void n64_virtualpak_write32(uint16_t address, uint8_t *tx_buff) memcpy(&n64_virtualpak_scratch[address], tx_buff, 32); } -void n64_virtualpak_update(n64_mempack *vpak) +void n64_virtualpak_update(n64_controllerpak *vpak) { n64_settings *settings = n64_settings_get(); if (settings == NULL) diff --git a/src/n64/n64_virtualpak.h b/src/n64/n64_virtualpak.h index 574cdcaf..30273b49 100644 --- a/src/n64/n64_virtualpak.h +++ b/src/n64/n64_virtualpak.h @@ -28,8 +28,8 @@ extern "C" { #define MENU_NAME_FIELD 0 #define MENU_EXT_FIELD 1 -void n64_virtualpak_init(n64_mempack *vpak); -void n64_virtualpak_update(n64_mempack *vpak); +void n64_virtualpak_init(n64_controllerpak *vpak); +void n64_virtualpak_update(n64_controllerpak *vpak); void n64_virtualpak_read32(uint16_t address, uint8_t *rx_buff); void n64_virtualpak_write32(uint16_t address, uint8_t *tx_buff); void n64_virtualpak_write_info_1(char* msg); diff --git a/src/tft.cpp b/src/tft.cpp index 3c22078d..3b9d1551 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -70,13 +70,13 @@ static const char *n64_peri_to_string(n64_input_dev_t *c) { case PERI_NONE: return "NO PERIPHERAL"; - case PERI_RUMBLE: - return "RUMBLE PAK"; - case PERI_MEMPAK: - if (c->mempack->virtual_is_active) - return "VIRTUAL PAK"; + case PERI_RPAK: + return "RUMBLE-PAK"; + case PERI_CPAK: + if (c->cpak->virtual_is_active) + return "VIRTUAL-PAK"; - snprintf(text_buff, sizeof(text_buff), "MPAK (BANK %u)", (unsigned int)c->mempack->id); + snprintf(text_buff, sizeof(text_buff), "CPAK (BANK %u)", (unsigned int)c->cpak->id); return text_buff; case PERI_TPAK: snprintf(text_buff, sizeof(text_buff), "TPAK (%s)", (c->tpak->gbcart->rom == NULL) ? "NO ROM" : c->tpak->gbcart->title); From f07995d2a024c145e74f0d45b5e72ba9c99aa2a9 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 28 Jan 2022 16:34:22 +0000 Subject: [PATCH 118/121] N64: Rename n64_mempak files --- src/n64/n64_controller.h | 2 +- src/n64/{n64_mempak.c => n64_controllerpak.c} | 56 ++++++++--------- src/n64/{n64_mempak.h => n64_controllerpak.h} | 60 +++++++++---------- 3 files changed, 59 insertions(+), 59 deletions(-) rename src/n64/{n64_mempak.c => n64_controllerpak.c} (95%) rename src/n64/{n64_mempak.h => n64_controllerpak.h} (88%) diff --git a/src/n64/n64_controller.h b/src/n64/n64_controller.h index bab4432c..ad5c99e8 100644 --- a/src/n64/n64_controller.h +++ b/src/n64/n64_controller.h @@ -9,7 +9,7 @@ extern "C" { #endif #include -#include "n64_mempak.h" +#include "n64_controllerpak.h" #include "n64_rumblepak.h" #include "n64_settings.h" #include "n64_virtualpak.h" diff --git a/src/n64/n64_mempak.c b/src/n64/n64_controllerpak.c similarity index 95% rename from src/n64/n64_mempak.c rename to src/n64/n64_controllerpak.c index 43ced3fe..e97d7d59 100644 --- a/src/n64/n64_mempak.c +++ b/src/n64/n64_controllerpak.c @@ -1,28 +1,28 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#include "n64_controller.h" - -void n64_cpak_read32(n64_controllerpak *cpak, uint16_t address, uint8_t *rx_buff) -{ - if (cpak->virtual_is_active) - { - n64_virtualpak_read32(address, rx_buff); - } - else - { - n64hal_read_extram(rx_buff, cpak->data, address, 32); - } -} - -void n64_cpak_write32(n64_controllerpak *cpak, uint16_t address, uint8_t *tx_buff) -{ - if (cpak->virtual_is_active) - { - n64_virtualpak_write32(address, tx_buff); - } - else - { - n64hal_write_extram(tx_buff, cpak->data, address, 32); - } -} +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#include "n64_controller.h" + +void n64_cpak_read32(n64_controllerpak *cpak, uint16_t address, uint8_t *rx_buff) +{ + if (cpak->virtual_is_active) + { + n64_virtualpak_read32(address, rx_buff); + } + else + { + n64hal_read_extram(rx_buff, cpak->data, address, 32); + } +} + +void n64_cpak_write32(n64_controllerpak *cpak, uint16_t address, uint8_t *tx_buff) +{ + if (cpak->virtual_is_active) + { + n64_virtualpak_write32(address, tx_buff); + } + else + { + n64hal_write_extram(tx_buff, cpak->data, address, 32); + } +} diff --git a/src/n64/n64_mempak.h b/src/n64/n64_controllerpak.h similarity index 88% rename from src/n64/n64_mempak.h rename to src/n64/n64_controllerpak.h index ffc5f83d..7c5f252c 100644 --- a/src/n64/n64_mempak.h +++ b/src/n64/n64_controllerpak.h @@ -1,30 +1,30 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#ifndef _N64_MEMPAK_h -#define _N64_MEMPAK_h - -#ifdef __cplusplus -extern "C" { -#endif - -#define CPAK_SIZE 32768 - -typedef struct -{ - uint32_t id; - uint8_t *data; - //Only if a 'virtual mempak' - uint32_t virtual_is_active; - uint32_t virtual_update_req; - uint32_t virtual_selected_row; -} n64_controllerpak; - -void n64_cpak_read32(n64_controllerpak *cpak, uint16_t address, uint8_t *rx_buff); -void n64_cpak_write32(n64_controllerpak *cpak, uint16_t address, uint8_t *tx_buff); - -#ifdef __cplusplus -} -#endif - -#endif +// Copyright 2020, Ryan Wendland, usb64 +// SPDX-License-Identifier: MIT + +#ifndef _N64_CONTROLLERPAK_h +#define _N64_CONTROLLERPAK_h + +#ifdef __cplusplus +extern "C" { +#endif + +#define CPAK_SIZE 32768 + +typedef struct +{ + uint32_t id; + uint8_t *data; + //Only if a 'virtual mempak' + uint32_t virtual_is_active; + uint32_t virtual_update_req; + uint32_t virtual_selected_row; +} n64_controllerpak; + +void n64_cpak_read32(n64_controllerpak *cpak, uint16_t address, uint8_t *rx_buff); +void n64_cpak_write32(n64_controllerpak *cpak, uint16_t address, uint8_t *tx_buff); + +#ifdef __cplusplus +} +#endif + +#endif From 36bba0af1c73004b6c65ffe68f27b189215fbc29 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Mon, 8 Aug 2022 15:23:11 +0930 Subject: [PATCH 119/121] Update submodules --- .gitmodules | 3 + platformio.ini | 12 +- src/lib/xinput_host.c | 488 ------------------------------------------ src/lib/xinput_host.h | 128 ----------- 4 files changed, 10 insertions(+), 621 deletions(-) delete mode 100644 src/lib/xinput_host.c delete mode 100644 src/lib/xinput_host.h diff --git a/.gitmodules b/.gitmodules index b87e9f42..120470b5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "src/lib/tinyalloc"] path = src/lib/tinyalloc url = https://github.com/thi-ng/tinyalloc.git +[submodule "src/lib/tusb_xinput"] + path = src/lib/tusb_xinput + url = https://github.com/Ryzee119/tusb_xinput.git diff --git a/platformio.ini b/platformio.ini index d8adca2b..47f52e4e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -34,6 +34,7 @@ src_filter = + + + + + build_flags = -O2 @@ -45,6 +46,7 @@ build_flags = -Isrc/lib/printf -Isrc/lib/tinyalloc -Isrc/lib/tinyusb/src + -Isrc/lib/tusb_xinput ;DEBUG OUTPUT CONFIG -DDEBUG_STATUS=1 ;General information -DDEBUG_N64=0 ;For debugging N64 low level info @@ -71,7 +73,7 @@ platform = teensy@~4.13.1 board = teensy41 framework = arduino -src_filter = +build_src_filter = ${common_env_data.src_filter} + + @@ -79,7 +81,7 @@ src_filter = + ;TinyUSB (T4 specific) + - + + + + build_flags = @@ -104,7 +106,7 @@ framework = stm32cube ; I also created code/data areas for flash when I want functions/data to remain on flash to save RAM. board_build.ldscript = src/port_stm32f7/stm37f750-dk/STM32F750N8HX_EXTFLASH.ld -src_filter = +build_src_filter = ${common_env_data.src_filter} + + @@ -133,7 +135,7 @@ framework = stm32cube extra_scripts = post:hex_from_elf.py board_build.ldscript = src/port_stm32f7/stm37f769-dk/STM32F769NIHX_FLASH.ld -src_filter = +build_src_filter = ${common_env_data.src_filter} + + @@ -159,7 +161,7 @@ build_flags = [env:template] platform = native -src_filter = +build_src_filter = ${common_env_data.src_filter} + + diff --git a/src/lib/xinput_host.c b/src/lib/xinput_host.c deleted file mode 100644 index 304d909a..00000000 --- a/src/lib/xinput_host.c +++ /dev/null @@ -1,488 +0,0 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#include "tusb_option.h" - -#if (TUSB_OPT_HOST_ENABLED && CFG_TUH_XINPUT) - -#include "host/usbh.h" -#include "host/usbh_classdriver.h" -#include "xinput_host.h" - -typedef struct -{ - uint8_t inst_count; - xinputh_interface_t instances[CFG_TUH_XINPUT]; -} xinputh_device_t; - -static xinputh_device_t _xinputh_dev[CFG_TUH_DEVICE_MAX]; - -TU_ATTR_ALWAYS_INLINE static inline xinputh_device_t *get_dev(uint8_t dev_addr) -{ - return &_xinputh_dev[dev_addr - 1]; -} - -TU_ATTR_ALWAYS_INLINE static inline xinputh_interface_t *get_instance(uint8_t dev_addr, uint8_t instance) -{ - return &_xinputh_dev[dev_addr - 1].instances[instance]; -} - -static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr) -{ - for (uint8_t inst = 0; inst < CFG_TUH_XINPUT; inst++) - { - xinputh_interface_t *hid = get_instance(dev_addr, inst); - - if ((ep_addr == hid->ep_in) || (ep_addr == hid->ep_out)) - return inst; - } - - return 0xff; -} - -static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf) -{ - for (uint8_t inst = 0; inst < CFG_TUH_XINPUT; inst++) - { - xinputh_interface_t *hid = get_instance(dev_addr, inst); - - if ((hid->itf_num == itf) && (hid->ep_in || hid->ep_out)) - return inst; - } - - return 0xff; -} - -static void wait_for_tx_complete(uint8_t dev_addr, uint8_t ep_out) -{ - while (usbh_edpt_busy(dev_addr, ep_out)) - tuh_task(); -} - -bool tuh_xinput_receive_report(uint8_t dev_addr, uint8_t instance) -{ - xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); - TU_VERIFY(usbh_edpt_claim(dev_addr, xid_itf->ep_in)); - return usbh_edpt_xfer(dev_addr, xid_itf->ep_in, xid_itf->epin_buf, xid_itf->epin_size); -} - -bool tuh_xinput_send_report(uint8_t dev_addr, uint8_t instance, const uint8_t *txbuf, uint16_t len) -{ - xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); - - TU_ASSERT(len <= xid_itf->epout_size); - TU_VERIFY(usbh_edpt_claim(dev_addr, xid_itf->ep_out)); - - memcpy(xid_itf->epout_buf, txbuf, len); - return usbh_edpt_xfer(dev_addr, xid_itf->ep_out, xid_itf->epout_buf, len); -} - -bool tuh_xinput_set_led(uint8_t dev_addr, uint8_t instance, uint8_t quadrant, bool block) -{ - xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); - uint8_t txbuf[32]; - uint16_t len; - switch (xid_itf->type) - { - case XBOX360_WIRELESS: - memcpy(txbuf, xbox360w_led, sizeof(xbox360w_led)); - txbuf[3] = (quadrant == 0) ? 0x40 : (0x40 | (quadrant + 5)); - len = sizeof(xbox360w_led); - break; - case XBOX360_WIRED: - memcpy(txbuf, xbox360_wired_led, sizeof(xbox360_wired_led)); - txbuf[2] = (quadrant == 0) ? 0 : (quadrant + 5); - len = sizeof(xbox360_wired_led); - break; - default: - return true; - } - bool ret = tuh_xinput_send_report(dev_addr, instance, txbuf, len); - if (block && ret) - { - wait_for_tx_complete(dev_addr, xid_itf->ep_out); - } - return ret; -} - -bool tuh_xinput_set_rumble(uint8_t dev_addr, uint8_t instance, uint8_t lValue, uint8_t rValue, bool block) -{ - xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); - uint8_t txbuf[32]; - uint16_t len; - - switch (xid_itf->type) - { - case XBOX360_WIRELESS: - memcpy(txbuf, xbox360w_rumble, sizeof(xbox360w_rumble)); - txbuf[5] = lValue; - txbuf[6] = rValue; - len = sizeof(xbox360w_rumble); - break; - case XBOX360_WIRED: - memcpy(txbuf, xbox360_wired_rumble, sizeof(xbox360_wired_rumble)); - txbuf[3] = lValue; - txbuf[4] = rValue; - len = sizeof(xbox360_wired_rumble); - break; - case XBOXONE: - memcpy(txbuf, xboxone_rumble, sizeof(xboxone_rumble)); - txbuf[8] = lValue / 2.6f; //Scale is 0 to 100 - txbuf[9] = rValue / 2.6f; //Scale is 0 to 100 - len = sizeof(xboxone_rumble); - break; - case XBOXOG: - memcpy(txbuf, xboxog_rumble, sizeof(xboxog_rumble)); - txbuf[2] = lValue; - txbuf[3] = lValue; - txbuf[4] = rValue; - txbuf[5] = rValue; - len = sizeof(xboxog_rumble); - break; - default: - return true; - } - bool ret = tuh_xinput_send_report(dev_addr, instance, txbuf, len); - if (block && ret) - { - wait_for_tx_complete(dev_addr, xid_itf->ep_out); - } - return true; -} - -//--------------------------------------------------------------------+ -// USBH API -//--------------------------------------------------------------------+ -void xinputh_init(void) -{ - tu_memclr(_xinputh_dev, sizeof(_xinputh_dev)); -} - -bool xinputh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) -{ - TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX); - - xinput_type_t type = XINPUT_UNKNOWN; - if (desc_itf->bNumEndpoints < 2) - type = XINPUT_UNKNOWN; - else if (desc_itf->bInterfaceSubClass == 0x5D && //Xbox360 wireless bInterfaceSubClass - desc_itf->bInterfaceProtocol == 0x81) //Xbox360 wireless bInterfaceProtocol - type = XBOX360_WIRELESS; - else if (desc_itf->bInterfaceSubClass == 0x5D && //Xbox360 wired bInterfaceSubClass - desc_itf->bInterfaceProtocol == 0x01) //Xbox360 wired bInterfaceProtocol - type = XBOX360_WIRED; - else if (desc_itf->bInterfaceSubClass == 0x47 && //Xbone and SX bInterfaceSubClass - desc_itf->bInterfaceProtocol == 0xD0) //Xbone and SX bInterfaceProtocol - type = XBOXONE; - else if (desc_itf->bInterfaceClass == 0x58 && //XboxOG bInterfaceClass - desc_itf->bInterfaceSubClass == 0x42) //XboxOG bInterfaceSubClass - type = XBOXOG; - - if (type == XINPUT_UNKNOWN) - { - TU_LOG2("XINPUT: Not a valid interface\n"); - return false; - } - - TU_LOG2("XINPUT opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr); - - xinputh_device_t *xinput_dev = get_dev(dev_addr); - TU_ASSERT(xinput_dev->inst_count < CFG_TUH_XINPUT, 0); - - xinputh_interface_t *xid_itf = get_instance(dev_addr, xinput_dev->inst_count); - xid_itf->itf_num = desc_itf->bInterfaceNumber; - xid_itf->type = type; - - //Parse descriptor for all endpoints and open them - uint8_t const *p_desc = (uint8_t const *)desc_itf; - int endpoint = 0; - int pos = 0; - while (endpoint < desc_itf->bNumEndpoints && pos < max_len) - { - if (tu_desc_type(p_desc) != TUSB_DESC_ENDPOINT) - { - pos += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - continue; - } - tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *)p_desc; - TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType); - TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep)); - if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT) - { - xid_itf->ep_out = desc_ep->bEndpointAddress; - xid_itf->epout_size = tu_edpt_packet_size(desc_ep); - } - else - { - xid_itf->ep_in = desc_ep->bEndpointAddress; - xid_itf->epin_size = tu_edpt_packet_size(desc_ep); - } - endpoint++; - pos += tu_desc_len(p_desc); - p_desc = tu_desc_next(p_desc); - } - - xinput_dev->inst_count++; - return true; -} - -bool xinputh_set_config(uint8_t dev_addr, uint8_t itf_num) -{ - uint8_t instance = get_instance_id_by_itfnum(dev_addr, itf_num); - xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); - xid_itf->connected = true; - - if (xid_itf->type == XBOX360_WIRELESS) - { - //Wireless controllers may not be connected yet. - xid_itf->connected = false; - tuh_xinput_send_report(dev_addr, instance, xbox360w_inquire_present, sizeof(xbox360w_inquire_present)); - wait_for_tx_complete(dev_addr, xid_itf->ep_out); - } - else if (xid_itf->type == XBOX360_WIRED) - { - } - else if (xid_itf->type == XBOXONE) - { - uint16_t PID, VID; - tuh_vid_pid_get(dev_addr, &VID, &PID); - - tuh_xinput_send_report(dev_addr, instance, xboxone_start_input, sizeof(xboxone_start_input)); - wait_for_tx_complete(dev_addr, xid_itf->ep_out); - - //Init packet for XBONE S/Elite controllers (return from bluetooth mode) - if (VID == 0x045e && (PID == 0x02ea || PID == 0x0b00)) - { - tuh_xinput_send_report(dev_addr, instance, xboxone_s_init, sizeof(xboxone_s_init)); - wait_for_tx_complete(dev_addr, xid_itf->ep_out); - } - - //Required for PDP aftermarket controllers - if (VID == 0x0e6f) - { - tuh_xinput_send_report(dev_addr, instance, xboxone_pdp_init1, sizeof(xboxone_pdp_init1)); - wait_for_tx_complete(dev_addr, xid_itf->ep_out); - tuh_xinput_send_report(dev_addr, instance, xboxone_pdp_init2, sizeof(xboxone_pdp_init2)); - wait_for_tx_complete(dev_addr, xid_itf->ep_out); - tuh_xinput_send_report(dev_addr, instance, xboxone_pdp_init3, sizeof(xboxone_pdp_init3)); - wait_for_tx_complete(dev_addr, xid_itf->ep_out); - } - } - - if (tuh_xinput_mount_cb) - { - tuh_xinput_mount_cb(dev_addr, instance, xid_itf); - } - return true; -} - -bool xinputh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ - if (result != XFER_RESULT_SUCCESS) - { - return false; - } - - uint8_t const dir = tu_edpt_dir(ep_addr); - uint8_t const instance = get_instance_id_by_epaddr(dev_addr, ep_addr); - xinputh_interface_t *xid_itf = get_instance(dev_addr, instance); - xinput_gamepad_t *pad = &xid_itf->pad; - uint8_t *rdata = xid_itf->epin_buf; - - if (dir == TUSB_DIR_IN) - { - TU_LOG2("Get Report callback (%u, %u, %u bytes)\r\n", dev_addr, instance, xferred_bytes); - TU_LOG2_MEM(xid_itf->epin_buf, xferred_bytes, 2); - if (xid_itf->type == XBOX360_WIRED) - { - #define GET_USHORT(a) (uint16_t)((a)[1] << 8 | (a)[0]) - #define GET_SHORT(a) ((int16_t)GET_USHORT(a)) - if (rdata[1] == 0x14) - { - tu_memclr(pad, sizeof(xinput_gamepad_t)); - uint16_t wButtons = rdata[3] << 8 | rdata[2]; - - //Map digital buttons - if (wButtons & (1 << 0)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_UP; - if (wButtons & (1 << 1)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; - if (wButtons & (1 << 2)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; - if (wButtons & (1 << 3)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; - if (wButtons & (1 << 4)) pad->wButtons |= XINPUT_GAMEPAD_START; - if (wButtons & (1 << 5)) pad->wButtons |= XINPUT_GAMEPAD_BACK; - if (wButtons & (1 << 6)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; - if (wButtons & (1 << 7)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; - if (wButtons & (1 << 8)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; - if (wButtons & (1 << 9)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; - if (wButtons & (1 << 12)) pad->wButtons |= XINPUT_GAMEPAD_A; - if (wButtons & (1 << 13)) pad->wButtons |= XINPUT_GAMEPAD_B; - if (wButtons & (1 << 14)) pad->wButtons |= XINPUT_GAMEPAD_X; - if (wButtons & (1 << 15)) pad->wButtons |= XINPUT_GAMEPAD_Y; - - //Map the left and right triggers - pad->bLeftTrigger = rdata[4]; - pad->bRightTrigger = rdata[5]; - - //Map analog sticks - pad->sThumbLX = rdata[7] << 8 | rdata[6]; - pad->sThumbLY = rdata[9] << 8 | rdata[8]; - pad->sThumbRX = rdata[11] << 8 | rdata[10]; - pad->sThumbRY = rdata[13] << 8 | rdata[12]; - - xid_itf->new_pad_data = true; - } - } - else if (xid_itf->type == XBOX360_WIRELESS) - { - //Connect/Disconnect packet - if (rdata[0] & 0x08) - { - if (rdata[1] != 0x00 && xid_itf->connected == false) - { - TU_LOG2("XINPUT: WIRELESS CONTROLLER CONNECTED\n"); - xid_itf->connected = true; - } - else if (rdata[1] == 0x00 && xid_itf->connected == true) - { - TU_LOG2("XINPUT: WIRELESS CONTROLLER DISCONNECTED\n"); - xid_itf->connected = false; - } - } - - //Button status packet - if ((rdata[1] & 1) && rdata[5] == 0x13) - { - tu_memclr(pad, sizeof(xinput_gamepad_t)); - uint16_t wButtons = rdata[7] << 8 | rdata[6]; - - //Map digital buttons - if (wButtons & (1 << 0)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_UP; - if (wButtons & (1 << 1)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; - if (wButtons & (1 << 2)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; - if (wButtons & (1 << 3)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; - if (wButtons & (1 << 4)) pad->wButtons |= XINPUT_GAMEPAD_START; - if (wButtons & (1 << 5)) pad->wButtons |= XINPUT_GAMEPAD_BACK; - if (wButtons & (1 << 6)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; - if (wButtons & (1 << 7)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; - if (wButtons & (1 << 8)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; - if (wButtons & (1 << 9)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; - if (wButtons & (1 << 12)) pad->wButtons |= XINPUT_GAMEPAD_A; - if (wButtons & (1 << 13)) pad->wButtons |= XINPUT_GAMEPAD_B; - if (wButtons & (1 << 14)) pad->wButtons |= XINPUT_GAMEPAD_X; - if (wButtons & (1 << 15)) pad->wButtons |= XINPUT_GAMEPAD_Y; - - //Map the left and right triggers - pad->bLeftTrigger = rdata[8]; - pad->bRightTrigger = rdata[9]; - - //Map analog sticks - pad->sThumbLX = rdata[11] << 8 | rdata[10]; - pad->sThumbLY = rdata[13] << 8 | rdata[12]; - pad->sThumbRX = rdata[15] << 8 | rdata[14]; - pad->sThumbRY = rdata[17] << 8 | rdata[16]; - - xid_itf->new_pad_data = true; - } - } - else if (xid_itf->type == XBOXONE) - { - if (rdata[0] == 0x20) - { - tu_memclr(pad, sizeof(xinput_gamepad_t)); - uint16_t wButtons = rdata[5] << 8 | rdata[4]; - - //Map digital buttons - if (wButtons & (1 << 8)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_UP; - if (wButtons & (1 << 9)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; - if (wButtons & (1 << 10)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; - if (wButtons & (1 << 11)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; - if (wButtons & (1 << 2)) pad->wButtons |= XINPUT_GAMEPAD_START; - if (wButtons & (1 << 3)) pad->wButtons |= XINPUT_GAMEPAD_BACK; - if (wButtons & (1 << 14)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; - if (wButtons & (1 << 15)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; - if (wButtons & (1 << 12)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; - if (wButtons & (1 << 13)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; - if (wButtons & (1 << 4)) pad->wButtons |= XINPUT_GAMEPAD_A; - if (wButtons & (1 << 5)) pad->wButtons |= XINPUT_GAMEPAD_B; - if (wButtons & (1 << 6)) pad->wButtons |= XINPUT_GAMEPAD_X; - if (wButtons & (1 << 7)) pad->wButtons |= XINPUT_GAMEPAD_Y; - - //Map the left and right triggers - pad->bLeftTrigger = (rdata[7] << 8 | rdata[6]) >> 2; - pad->bRightTrigger = (rdata[9] << 8 | rdata[8]) >> 2; - - //Map analog sticks - pad->sThumbLX = rdata[11] << 8 | rdata[10]; - pad->sThumbLY = rdata[13] << 8 | rdata[12]; - pad->sThumbRX = rdata[15] << 8 | rdata[14]; - pad->sThumbRY = rdata[17] << 8 | rdata[16]; - - xid_itf->new_pad_data = true; - } - } - else if (xid_itf->type == XBOXOG) - { - if (rdata[1] == 0x14) - { - tu_memclr(pad, sizeof(xinput_gamepad_t)); - uint16_t wButtons = rdata[3] << 8 | rdata[2]; - - //Map digital buttons - if (wButtons & (1 << 0)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_UP; - if (wButtons & (1 << 1)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; - if (wButtons & (1 << 2)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; - if (wButtons & (1 << 3)) pad->wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; - if (wButtons & (1 << 4)) pad->wButtons |= XINPUT_GAMEPAD_START; - if (wButtons & (1 << 5)) pad->wButtons |= XINPUT_GAMEPAD_BACK; - if (wButtons & (1 << 6)) pad->wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; - if (wButtons & (1 << 7)) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; - - if (rdata[4] > 0x20) pad->wButtons |= XINPUT_GAMEPAD_A; - if (rdata[5] > 0x20) pad->wButtons |= XINPUT_GAMEPAD_B; - if (rdata[6] > 0x20) pad->wButtons |= XINPUT_GAMEPAD_X; - if (rdata[7] > 0x20) pad->wButtons |= XINPUT_GAMEPAD_Y; - if (rdata[8] > 0x20) pad->wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; - if (rdata[9] > 0x20) pad->wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; - - //Map the left and right triggers - pad->bLeftTrigger = rdata[10]; - pad->bRightTrigger = rdata[11]; - - //Map analog sticks - pad->sThumbLX = rdata[13] << 8 | rdata[12]; - pad->sThumbLY = rdata[15] << 8 | rdata[14]; - pad->sThumbRX = rdata[17] << 8 | rdata[16]; - pad->sThumbRY = rdata[19] << 8 | rdata[18]; - - xid_itf->new_pad_data = true; - } - } - tuh_xinput_report_received_cb(dev_addr, instance, (const uint8_t *)xid_itf, sizeof(xinputh_interface_t)); - xid_itf->new_pad_data = false; - } - else - { - if (tuh_xinput_report_sent_cb) - { - tuh_xinput_report_sent_cb(dev_addr, instance, xid_itf->epout_buf, xferred_bytes); - } - } - - return true; -} - -void xinputh_close(uint8_t dev_addr) -{ - xinputh_device_t *xinput_dev = get_dev(dev_addr); - - for (uint8_t inst = 0; inst < xinput_dev->inst_count; inst++) - { - if (tuh_xinput_umount_cb) - { - tuh_xinput_umount_cb(dev_addr, inst); - } - } - tu_memclr(xinput_dev, sizeof(xinputh_device_t)); -} - -#endif diff --git a/src/lib/xinput_host.h b/src/lib/xinput_host.h deleted file mode 100644 index 489b10f1..00000000 --- a/src/lib/xinput_host.h +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2020, Ryan Wendland, usb64 -// SPDX-License-Identifier: MIT - -#ifndef _TUSB_XINPUT_HOST_H_ -#define _TUSB_XINPUT_HOST_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// Class Driver Configuration -//--------------------------------------------------------------------+ - -#ifndef CFG_TUH_XINPUT_EPIN_BUFSIZE -#define CFG_TUH_XINPUT_EPIN_BUFSIZE 64 -#endif - -#ifndef CFG_TUH_XINPUT_EPOUT_BUFSIZE -#define CFG_TUH_XINPUT_EPOUT_BUFSIZE 64 -#endif - -//XINPUT defines and struct format from -//https://docs.microsoft.com/en-us/windows/win32/api/xinput/ns-xinput-xinput_gamepad -#define XINPUT_GAMEPAD_DPAD_UP 0x0001 -#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002 -#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004 -#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008 -#define XINPUT_GAMEPAD_START 0x0010 -#define XINPUT_GAMEPAD_BACK 0x0020 -#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040 -#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080 -#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 -#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200 -#define XINPUT_GAMEPAD_A 0x1000 -#define XINPUT_GAMEPAD_B 0x2000 -#define XINPUT_GAMEPAD_X 0x4000 -#define XINPUT_GAMEPAD_Y 0x8000 -#define MAX_PACKET_SIZE 32 - -typedef struct xinput_gamepad -{ - uint16_t wButtons; - uint8_t bLeftTrigger; - uint8_t bRightTrigger; - int16_t sThumbLX; - int16_t sThumbLY; - int16_t sThumbRX; - int16_t sThumbRY; -} xinput_gamepad_t; - -typedef enum -{ - XINPUT_UNKNOWN = 0, - XBOXONE, - XBOX360_WIRELESS, - XBOX360_WIRED, - XBOXOG -} xinput_type_t; - -typedef struct -{ - xinput_type_t type; - xinput_gamepad_t pad; - uint8_t connected; - uint8_t new_pad_data; - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - - uint16_t epin_size; - uint16_t epout_size; - - uint8_t epin_buf[CFG_TUH_XINPUT_EPIN_BUFSIZE]; - uint8_t epout_buf[CFG_TUH_XINPUT_EPOUT_BUFSIZE]; -} xinputh_interface_t; - -void tuh_xinput_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); -TU_ATTR_WEAK void tuh_xinput_report_sent_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len); -TU_ATTR_WEAK void tuh_xinput_umount_cb(uint8_t dev_addr, uint8_t instance); -TU_ATTR_WEAK void tuh_xinput_mount_cb(uint8_t dev_addr, uint8_t instance, const xinputh_interface_t *xinput_itf); -bool tuh_xinput_receive_report(uint8_t dev_addr, uint8_t instance); -bool tuh_xinput_send_report(uint8_t dev_addr, uint8_t instance, const uint8_t *txbuf, uint16_t len); -bool tuh_xinput_set_led(uint8_t dev_addr, uint8_t instance, uint8_t quadrant, bool block); -bool tuh_xinput_set_rumble(uint8_t dev_addr, uint8_t instance, uint8_t lValue, uint8_t rValue, bool block); - -//--------------------------------------------------------------------+ -// Internal Class Driver API -//--------------------------------------------------------------------+ -void xinputh_init (void); -bool xinputh_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len); -bool xinputh_set_config (uint8_t dev_addr, uint8_t itf_num); -bool xinputh_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); -void xinputh_close (uint8_t dev_addr); - -//Wired 360 commands -static const uint8_t xbox360_wired_rumble[] = {0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const uint8_t xbox360_wired_led[] = {0x01, 0x03, 0x00}; - -//Xbone one -static const uint8_t xboxone_start_input[] = {0x05, 0x20, 0x03, 0x01, 0x00}; -static const uint8_t xboxone_s_init[] = {0x05, 0x20, 0x00, 0x0f, 0x06}; -static const uint8_t xboxone_pdp_init1[] = {0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14}; -static const uint8_t xboxone_pdp_init2[] = {0x06, 0x30}; -static const uint8_t xboxone_pdp_init3[] = {0x06, 0x20, 0x00, 0x02, 0x01, 0x00}; -static const uint8_t xboxone_rumble[] = {0x09, 0x00, 0x00, 0x09, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB}; - -//Wireless 360 commands -static const uint8_t xbox360w_led[] = {0x00, 0x00, 0x08, 0x40}; -//Sending 0x00, 0x00, 0x08, 0x00 will permanently disable rumble until you do this: -static const uint8_t xbox360w_rumble_enable[] = {0x00, 0x00, 0x08, 0x01}; -static const uint8_t xbox360w_rumble[] = {0x00, 0x01, 0x0F, 0xC0, 0x00, 0x00}; -static const uint8_t xbox360w_inquire_present[] = {0x08, 0x00, 0x0F, 0xC0}; -static const uint8_t xbox360w_controller_info[] = {0x00, 0x00, 0x00, 0x40}; -static const uint8_t xbox360w_unknown[] = {0x00, 0x00, 0x02, 0x80}; -static const uint8_t xbox360w_power_off[] = {0x00, 0x00, 0x08, 0xC0}; -static const uint8_t xbox360w_chatpad_init[] = {0x00, 0x00, 0x0C, 0x1B}; -static const uint8_t xbox360w_chatpad_keepalive1[] = {0x00, 0x00, 0x0C, 0x1F}; -static const uint8_t xbox360w_chatpad_keepalive2[] = {0x00, 0x00, 0x0C, 0x1E}; - -//Original Xbox -static const uint8_t xboxog_rumble[] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00}; - -#ifdef __cplusplus -} -#endif - -#endif /* _TUSB_XINPUT_HOST_H_ */ From c13bc0c88e758d1ecf5eaa8534d92b7627370e0f Mon Sep 17 00:00:00 2001 From: Ryan Wendland Date: Wed, 21 Sep 2022 08:33:56 +0930 Subject: [PATCH 120/121] TFT: Use lvgl instead of guilite --- .gitmodules | 3 + platformio.ini | 17 +- src/lib/GuiLite.h | 4343 ---------------------------------- src/lib/lv_conf.h | 742 ++++++ src/lib/lvgl | 1 + src/main.cpp | 37 +- src/n64/n64_controller.h | 1 + src/port_teensy41/hal_t4.cpp | 1 + src/port_teensy41/tft_t4.cpp | 114 +- src/tft.cpp | 317 ++- src/tft.h | 17 +- src/tft/Arial_14.cpp | 269 --- src/tft/Arial_19.cpp | 269 --- 13 files changed, 971 insertions(+), 5160 deletions(-) delete mode 100644 src/lib/GuiLite.h create mode 100644 src/lib/lv_conf.h create mode 160000 src/lib/lvgl delete mode 100644 src/tft/Arial_14.cpp delete mode 100644 src/tft/Arial_19.cpp diff --git a/.gitmodules b/.gitmodules index 120470b5..d6a7ded5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "src/lib/tusb_xinput"] path = src/lib/tusb_xinput url = https://github.com/Ryzee119/tusb_xinput.git +[submodule "src/lib/lvgl"] + path = src/lib/lvgl + url = https://github.com/lvgl/lvgl.git diff --git a/platformio.ini b/platformio.ini index 47f52e4e..5fbf19a5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -36,6 +36,17 @@ src_filter = + + + + + + + + + + + + + + + + + + + + + + + build_flags = -O2 -Wall @@ -68,8 +79,12 @@ build_flags = ; Tinyalloc Configuration -DTA_DISABLE_COMPACT + ; LVGL Configuration + -Isrc/lib/lvgl + -DLV_LVGL_H_INCLUDE_SIMPLE + [env:teensy41] -platform = teensy@~4.13.1 +platform = teensy@~4.16.0 board = teensy41 framework = arduino diff --git a/src/lib/GuiLite.h b/src/lib/GuiLite.h deleted file mode 100644 index b6652636..00000000 --- a/src/lib/GuiLite.h +++ /dev/null @@ -1,4343 +0,0 @@ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wreorder" -#pragma GCC diagnostic ignored "-Wsign-compare" -#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" - -#pragma once - -#define REAL_TIME_TASK_CYCLE_MS 50 -#define MAX(a,b) (((a)>(b))?(a):(b)) -#define MIN(a,b) (((a)<(b))?(a):(b)) - -#define GL_ARGB(a, r, g, b) ((((unsigned int)(a)) << 24) | (((unsigned int)(r)) << 16) | (((unsigned int)(g)) << 8) | ((unsigned int)(b))) -#define GL_ARGB_A(rgb) ((((unsigned int)(rgb)) >> 24) & 0xFF) - -#define GL_RGB(r, g, b) ((0xFF << 24) | (((unsigned int)(r)) << 16) | (((unsigned int)(g)) << 8) | ((unsigned int)(b))) -#define GL_RGB_R(rgb) ((((unsigned int)(rgb)) >> 16) & 0xFF) -#define GL_RGB_G(rgb) ((((unsigned int)(rgb)) >> 8) & 0xFF) -#define GL_RGB_B(rgb) (((unsigned int)(rgb)) & 0xFF) -#define GL_RGB_32_to_16(rgb) (((((unsigned int)(rgb)) & 0xFF) >> 3) | ((((unsigned int)(rgb)) & 0xFC00) >> 5) | ((((unsigned int)(rgb)) & 0xF80000) >> 8)) -#define GL_RGB_16_to_32(rgb) ((0xFF << 24) | ((((unsigned int)(rgb)) & 0x1F) << 3) | ((((unsigned int)(rgb)) & 0x7E0) << 5) | ((((unsigned int)(rgb)) & 0xF800) << 8)) - -#define ALIGN_HCENTER 0x00000000L -#define ALIGN_LEFT 0x01000000L -#define ALIGN_RIGHT 0x02000000L -#define ALIGN_HMASK 0x03000000L - -#define ALIGN_VCENTER 0x00000000L -#define ALIGN_TOP 0x00100000L -#define ALIGN_BOTTOM 0x00200000L -#define ALIGN_VMASK 0x00300000L - -typedef struct -{ - unsigned short year; - unsigned short month; - unsigned short date; - unsigned short day; - unsigned short hour; - unsigned short minute; - unsigned short second; -}T_TIME; - -void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)); -void _assert(const char* file, int line); -#define ASSERT(condition) \ - do{ \ - if(!(condition))_assert(__FILE__, __LINE__);\ - }while(0) -void log_out(const char* log); - -long get_time_in_second(); -T_TIME second_to_day(long second); -T_TIME get_time(); - -void start_real_timer(void (*func)(void* arg)); -void register_timer(int milli_second, void func(void* param), void* param); - -unsigned int get_cur_thread_id(); -void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg); -void thread_sleep(unsigned int milli_seconds); -int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data); - -#define FIFO_BUFFER_LEN 1024 -class c_fifo -{ -public: - c_fifo(); - int read(void* buf, int len); - int write(void* buf, int len); -private: - unsigned char m_buf[FIFO_BUFFER_LEN]; - int m_head; - int m_tail; - void* m_read_sem; - void* m_write_mutex; -}; - -class c_rect -{ -public: - c_rect(){ m_left = m_top = m_right = m_bottom = -1; } - c_rect(int left, int top, int width, int height) - { - set_rect(left, top, width, height); - } - void set_rect(int left, int top, int width, int height) - { - ASSERT(width > 0 && height > 0); - m_left = left; - m_top = top; - m_right = left + width - 1; - m_bottom = top + height -1; - } - bool pt_in_rect(int x, int y) const - { - return x >= m_left && x <= m_right && y >= m_top && y <= m_bottom; - } - int operator==(const c_rect& rect) const - { - return (m_left == rect.m_left) && (m_top == rect.m_top) && (m_right == rect.m_right) && (m_bottom == rect.m_bottom); - } - int width() const { return m_right - m_left + 1; } - int height() const { return m_bottom - m_top + 1 ; } - - int m_left; - int m_top; - int m_right; - int m_bottom; -}; -//BITMAP -typedef struct struct_bitmap_info -{ - unsigned short width; - unsigned short height; - unsigned short color_bits;//support 16 bits only - const unsigned short* pixel_color_array; -} BITMAP_INFO; -//FONT -typedef struct struct_lattice -{ - unsigned int utf8_code; - unsigned char width; - const unsigned char* pixel_buffer; -} LATTICE; -typedef struct struct_lattice_font_info -{ - unsigned char height; - unsigned int count; - LATTICE* lattice_array; -} LATTICE_FONT_INFO; -//Rebuild gui library once you change this file -enum FONT_LIST -{ - FONT_NULL, - FONT_DEFAULT, - FONT_CUSTOM1, - FONT_CUSTOM2, - FONT_CUSTOM3, - FONT_CUSTOM4, - FONT_CUSTOM5, - FONT_CUSTOM6, - FONT_MAX -}; -enum IMAGE_LIST -{ - IMAGE_CUSTOM1, - IMAGE_CUSTOM2, - IMAGE_CUSTOM3, - IMAGE_CUSTOM4, - IMAGE_CUSTOM5, - IMAGE_CUSTOM6, - IMAGE_MAX -}; -enum COLOR_LIST -{ - COLOR_WND_FONT, - COLOR_WND_NORMAL, - COLOR_WND_PUSHED, - COLOR_WND_FOCUS, - COLOR_WND_BORDER, - COLOR_CUSTOME1, - COLOR_CUSTOME2, - COLOR_CUSTOME3, - COLOR_CUSTOME4, - COLOR_CUSTOME5, - COLOR_CUSTOME6, - COLOR_MAX -}; -class c_theme -{ -public: - static int add_font(FONT_LIST index, const void* font) - { - if (index >= FONT_MAX) - { - ASSERT(false); - return -1; - } - s_font_map[index] = font; - return 0; - } - static const void* get_font(FONT_LIST index) - { - if (index >= FONT_MAX) - { - ASSERT(false); - return 0; - } - return s_font_map[index]; - } - static int add_image(IMAGE_LIST index, const void* image_info) - { - if (index >= IMAGE_MAX) - { - ASSERT(false); - return -1; - } - s_image_map[index] = image_info; - return 0; - } - static const void* get_image(IMAGE_LIST index) - { - if (index >= IMAGE_MAX) - { - ASSERT(false); - return 0; - } - return s_image_map[index]; - } - - static int add_color(COLOR_LIST index, const unsigned int color) - { - if (index >= COLOR_MAX) - { - ASSERT(false); - return -1; - } - s_color_map[index] = color; - return 0; - } - static const unsigned int get_color(COLOR_LIST index) - { - if (index >= COLOR_MAX) - { - ASSERT(false); - return 0; - } - return s_color_map[index]; - } -private: - static const void* s_font_map[FONT_MAX]; - static const void* s_image_map[IMAGE_MAX]; - static unsigned int s_color_map[COLOR_MAX]; -}; -#include -#include -#include -#define SURFACE_CNT_MAX 6//root + pages -typedef enum -{ - Z_ORDER_LEVEL_0,//lowest graphic level - Z_ORDER_LEVEL_1,//middle graphic level - Z_ORDER_LEVEL_2,//highest graphic level - Z_ORDER_LEVEL_MAX -}Z_ORDER_LEVEL; -struct EXTERNAL_GFX_OP -{ - void(*draw_pixel)(int x, int y, unsigned int rgb); - void(*fill_rect)(int x0, int y0, int x1, int y1, unsigned int rgb); -}; -class c_surface; -class c_display { - friend class c_surface; -public: - inline c_display(void* phy_fb, int display_width, int display_height, int surface_width, int surface_height, unsigned int color_bytes, int surface_cnt, EXTERNAL_GFX_OP* gfx_op = 0);//multiple surface or surface_no_fb - inline c_display(void* phy_fb, int display_width, int display_height, c_surface* surface);//single custom surface - inline c_surface* alloc_surface(Z_ORDER_LEVEL max_zorder, c_rect layer_rect = c_rect());//for multiple surfaces - inline int swipe_surface(c_surface* s0, c_surface* s1, int x0, int x1, int y0, int y1, int offset); - int get_width() { return m_width; } - int get_height() { return m_height; } - void* get_updated_fb(int* width, int* height, bool force_update = false) - { - if (width && height) - { - *width = get_width(); - *height = get_height(); - } - if (force_update) - { - return m_phy_fb; - } - if (m_phy_read_index == m_phy_write_index) - {//No update - return 0; - } - m_phy_read_index = m_phy_write_index; - return m_phy_fb; - } - int snap_shot(const char* file_name) - { - if (!m_phy_fb || (m_color_bytes !=2 && m_color_bytes != 4)) - { - return -1; - } - int width = get_width(); - int height = get_height(); - //16 bits framebuffer - if (m_color_bytes == 2) - { - return build_bmp(file_name, width, height, (unsigned char*)m_phy_fb); - } - //32 bits framebuffer - unsigned short* p_bmp565_data = new unsigned short[width * height]; - unsigned int* p_raw_data = (unsigned int*)m_phy_fb; - for (int i = 0; i < width * height; i++) - { - unsigned int rgb = *p_raw_data++; - p_bmp565_data[i] = GL_RGB_32_to_16(rgb); - } - int ret = build_bmp(file_name, width, height, (unsigned char*)p_bmp565_data); - delete[]p_bmp565_data; - return ret; - } -private: - int m_width; //in pixels - int m_height; //in pixels - int m_color_bytes; //16 bits, 32 bits only - void* m_phy_fb; //physical framebuffer - int m_phy_read_index; - int m_phy_write_index; - c_surface* m_surface_group[SURFACE_CNT_MAX]; - int m_surface_cnt; //surface count - int m_surface_index; -}; -class c_layer -{ -public: - c_layer() { fb = 0; } - void* fb; //framebuffer - c_rect rect; //framebuffer area -}; -class c_surface { - friend class c_display; friend class c_bitmap_operator; -public: - c_surface(unsigned int width, unsigned int height, unsigned int color_bytes, Z_ORDER_LEVEL max_zorder = Z_ORDER_LEVEL_0, c_rect overlpa_rect = c_rect()) : m_width(width), m_height(height), m_color_bytes(color_bytes), m_fb(0), m_is_active(false), m_top_zorder(Z_ORDER_LEVEL_0), m_phy_fb(0), m_phy_write_index(0), m_display(0) - { - (overlpa_rect == c_rect()) ? set_surface(max_zorder, c_rect(0, 0, width - 1, height - 1)) : set_surface(max_zorder, overlpa_rect); - } - int get_width() { return m_width; } - int get_height() { return m_height; } - unsigned int get_pixel(int x, int y, unsigned int z_order) - { - if (x >= m_width || y >= m_height || x < 0 || y < 0 || z_order >= Z_ORDER_LEVEL_MAX) - { - ASSERT(false); - return 0; - } - if (m_layers[z_order].fb) - { - return (m_color_bytes == 4) ? ((unsigned int*)(m_layers[z_order].fb))[y * m_width + x] : GL_RGB_16_to_32(((unsigned short*)(m_layers[z_order].fb))[y * m_width + x]); - } - else if (m_fb) - { - return (m_color_bytes == 4) ? ((unsigned int*)m_fb)[y * m_width + x] : GL_RGB_16_to_32(((unsigned short*)m_fb)[y * m_width + x]); - } - else if (m_phy_fb) - { - return (m_color_bytes == 4) ? ((unsigned int*)m_phy_fb)[y * m_width + x] : GL_RGB_16_to_32(((unsigned short*)m_phy_fb)[y * m_width + x]); - } - return 0; - } - virtual void draw_pixel(int x, int y, unsigned int rgb, unsigned int z_order) - { - if (x >= m_width || y >= m_height || x < 0 || y < 0) - { - return; - } - if (z_order > (unsigned int)m_max_zorder) - { - ASSERT(false); - return; - } - if (z_order == m_max_zorder) - { - return draw_pixel_on_fb(x, y, rgb); - } - - if (z_order > (unsigned int)m_top_zorder) - { - m_top_zorder = (Z_ORDER_LEVEL)z_order; - } - if (m_layers[z_order].rect.pt_in_rect(x, y)) - { - c_rect layer_rect = m_layers[z_order].rect; - if (m_color_bytes == 4) - { - ((unsigned int*)(m_layers[z_order].fb))[(x - layer_rect.m_left) + (y - layer_rect.m_top) * layer_rect.width()] = rgb; - } - else - { - ((unsigned short*)(m_layers[z_order].fb))[(x - layer_rect.m_left) + (y - layer_rect.m_top) * layer_rect.width()] = GL_RGB_32_to_16(rgb); - } - } - - if (z_order == m_top_zorder) - { - return draw_pixel_on_fb(x, y, rgb); - } - bool be_overlapped = false; - for (unsigned int tmp_z_order = Z_ORDER_LEVEL_MAX - 1; tmp_z_order > z_order; tmp_z_order--) - { - if (m_layers[tmp_z_order].rect.pt_in_rect(x, y)) - { - be_overlapped = true; - break; - } - } - if (!be_overlapped) - { - draw_pixel_on_fb(x, y, rgb); - } - } - virtual void fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb, unsigned int z_order) - { - x0 = (x0 < 0) ? 0 : x0; - y0 = (y0 < 0) ? 0 : y0; - x1 = (x1 > (m_width - 1)) ? (m_width - 1) : x1; - y1 = (y1 > (m_height - 1)) ? (m_height - 1) : y1; - if (z_order == m_max_zorder) - { - return fill_rect_on_fb(x0, y0, x1, y1, rgb); - } - if (z_order == m_top_zorder) - { - int x, y; - c_rect layer_rect = m_layers[z_order].rect; - unsigned int rgb_16 = GL_RGB_32_to_16(rgb); - for (y = y0; y <= y1; y++) - { - for (x = x0; x <= x1; x++) - { - if (layer_rect.pt_in_rect(x, y)) - { - if (m_color_bytes == 4) - { - ((unsigned int*)m_layers[z_order].fb)[(y - layer_rect.m_top) * layer_rect.width() + (x - layer_rect.m_left)] = rgb; - } - else - { - ((unsigned short*)m_layers[z_order].fb)[(y - layer_rect.m_top) * layer_rect.width() + (x - layer_rect.m_left)] = rgb_16; - } - } - } - } - return fill_rect_on_fb(x0, y0, x1, y1, rgb); - } - for (; y0 <= y1; y0++) - { - draw_hline(x0, x1, y0, rgb, z_order); - } - } - void draw_hline(int x0, int x1, int y, unsigned int rgb, unsigned int z_order) - { - for (; x0 <= x1; x0++) - { - draw_pixel(x0, y, rgb, z_order); - } - } - void draw_vline(int x, int y0, int y1, unsigned int rgb, unsigned int z_order) - { - for (; y0 <= y1; y0++) - { - draw_pixel(x, y0, rgb, z_order); - } - } - void draw_line(int x1, int y1, int x2, int y2, unsigned int rgb, unsigned int z_order) - { - int dx, dy, x, y, e; - (x1 > x2) ? (dx = x1 - x2) : (dx = x2 - x1); - (y1 > y2) ? (dy = y1 - y2) : (dy = y2 - y1); - if (((dx > dy) && (x1 > x2)) || ((dx <= dy) && (y1 > y2))) - { - x = x2; y = y2; - x2 = x1; y2 = y1; - x1 = x; y1 = y; - } - x = x1; y = y1; - if (dx > dy) - { - e = dy - dx / 2; - for (; x1 <= x2; ++x1, e += dy) - { - draw_pixel(x1, y1, rgb, z_order); - if (e > 0) { e -= dx; (y > y2) ? --y1 : ++y1; } - } - } - else - { - e = dx - dy / 2; - for (; y1 <= y2; ++y1, e += dx) - { - draw_pixel(x1, y1, rgb, z_order); - if (e > 0) { e -= dy; (x > x2) ? --x1 : ++x1; } - } - } - } - void draw_rect(int x0, int y0, int x1, int y1, unsigned int rgb, unsigned int z_order, unsigned int size = 1) - { - for (unsigned int offset = 0; offset < size; offset++) - { - draw_hline(x0 + offset, x1 - offset, y0 + offset, rgb, z_order); - draw_hline(x0 + offset, x1 - offset, y1 - offset, rgb, z_order); - draw_vline(x0 + offset, y0 + offset, y1 - offset, rgb, z_order); - draw_vline(x1 - offset, y0 + offset, y1 - offset, rgb, z_order); - } - } - void draw_rect(c_rect rect, unsigned int rgb, unsigned int size, unsigned int z_order) - { - draw_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, rgb, z_order, size); - } - void fill_rect(c_rect rect, unsigned int rgb, unsigned int z_order) - { - fill_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, rgb, z_order); - } - int flush_screen(int left, int top, int right, int bottom) - { - if (left < 0 || left >= m_width || right < 0 || right >= m_width || - top < 0 || top >= m_height || bottom < 0 || bottom >= m_height) - { - ASSERT(false); - } - if (!m_is_active || (0 == m_phy_fb) || (0 == m_fb)) - { - return -1; - } - int display_width = m_display->get_width(); - int display_height = m_display->get_height(); - left = (left >= display_width) ? (display_width - 1) : left; - right = (right >= display_width) ? (display_width - 1) : right; - top = (top >= display_height) ? (display_height - 1) : top; - bottom = (bottom >= display_height) ? (display_height - 1) : bottom; - for (int y = top; y < bottom; y++) - { - void* s_addr = (char*)m_fb + ((y * m_width + left) * m_color_bytes); - void* d_addr = (char*)m_phy_fb + ((y * display_width + left) * m_color_bytes); - memcpy(d_addr, s_addr, (right - left) * m_color_bytes); - } - *m_phy_write_index = *m_phy_write_index + 1; - return 0; - } - bool is_active() { return m_is_active; } - c_display* get_display() { return m_display; } - int show_layer(c_rect& rect, unsigned int z_order) - { - ASSERT(z_order >= Z_ORDER_LEVEL_0 && z_order < Z_ORDER_LEVEL_MAX); - c_rect layer_rect = m_layers[z_order].rect; - ASSERT(rect.m_left >= layer_rect.m_left && rect.m_right <= layer_rect.m_right && - rect.m_top >= layer_rect.m_top && rect.m_bottom <= layer_rect.m_bottom); - void* fb = m_layers[z_order].fb; - int width = layer_rect.width(); - for (int y = rect.m_top; y <= rect.m_bottom; y++) - { - for (int x = rect.m_left; x <= rect.m_right; x++) - { - unsigned int rgb = (m_color_bytes == 4) ? ((unsigned int*)fb)[(x - layer_rect.m_left) + (y - layer_rect.m_top) * width] : GL_RGB_16_to_32(((unsigned short*)fb)[(x - layer_rect.m_left) + (y - layer_rect.m_top) * width]); - draw_pixel_on_fb(x, y, rgb); - } - } - return 0; - } - void set_active(bool flag) { m_is_active = flag; } -protected: - virtual void fill_rect_on_fb(int x0, int y0, int x1, int y1, unsigned int rgb) - { - int display_width = m_display->get_width(); - int display_height = m_display->get_height(); - if (m_color_bytes == 4) - { - int x; - unsigned int* fb, * phy_fb; - for (; y0 <= y1; y0++) - { - x = x0; - fb = m_fb ? &((unsigned int*)m_fb)[y0 * m_width + x] : 0; - phy_fb = &((unsigned int*)m_phy_fb)[y0 * display_width + x]; - *m_phy_write_index = *m_phy_write_index + 1; - for (; x <= x1; x++) - { - if (fb) - { - *fb++ = rgb; - } - if (m_is_active && (x < display_width) && (y0 < display_height)) - { - *phy_fb++ = rgb; - } - } - } - } - else if (m_color_bytes == 2) - { - int x; - unsigned short* fb, * phy_fb; - rgb = GL_RGB_32_to_16(rgb); - for (; y0 <= y1; y0++) - { - x = x0; - fb = m_fb ? &((unsigned short*)m_fb)[y0 * m_width + x] : 0; - phy_fb = &((unsigned short*)m_phy_fb)[y0 * display_width + x]; - *m_phy_write_index = *m_phy_write_index + 1; - for (; x <= x1; x++) - { - if (fb) - { - *fb++ = rgb; - } - if (m_is_active && (x < display_width) && (y0 < display_height)) - { - *phy_fb++ = rgb; - } - } - } - } - } - virtual void draw_pixel_on_fb(int x, int y, unsigned int rgb) - { - if (m_fb) - { - (m_color_bytes == 4) ? ((unsigned int*)m_fb)[y * m_width + x] = rgb : ((unsigned short*)m_fb)[y * m_width + x] = GL_RGB_32_to_16(rgb); - } - if (m_is_active && (x < m_display->get_width()) && (y < m_display->get_height())) - { - if (m_color_bytes == 4) - { - ((unsigned int*)m_phy_fb)[y * (m_display->get_width()) + x] = rgb; - } - else - { - ((unsigned short*)m_phy_fb)[y * (m_display->get_width()) + x] = GL_RGB_32_to_16(rgb); - } - *m_phy_write_index = *m_phy_write_index + 1; - } - } - void attach_display(c_display* display) - { - ASSERT(display); - m_display = display; - m_phy_fb = display->m_phy_fb; - m_phy_write_index = &display->m_phy_write_index; - } - void set_surface(Z_ORDER_LEVEL max_z_order, c_rect layer_rect) - { - m_max_zorder = max_z_order; - if (m_display && (m_display->m_surface_cnt > 1)) - { - m_fb = calloc(m_width * m_height, m_color_bytes); - } - for (int i = Z_ORDER_LEVEL_0; i < m_max_zorder; i++) - {//Top layber fb always be 0 - ASSERT(m_layers[i].fb = calloc(layer_rect.width() * layer_rect.height(), m_color_bytes)); - m_layers[i].rect = layer_rect; - } - } - int m_width; //in pixels - int m_height; //in pixels - int m_color_bytes; //16 bits, 32 bits only - void* m_fb; //frame buffer you could see - c_layer m_layers[Z_ORDER_LEVEL_MAX];//all graphic layers - bool m_is_active; //active flag - Z_ORDER_LEVEL m_max_zorder; //the highest graphic layer the surface will have - Z_ORDER_LEVEL m_top_zorder; //the current highest graphic layer the surface have - void* m_phy_fb; //physical framebufer - int* m_phy_write_index; - c_display* m_display; -}; -class c_surface_no_fb : public c_surface {//No physical framebuffer, render with external graphic interface - friend class c_display; -public: - c_surface_no_fb(unsigned int width, unsigned int height, unsigned int color_bytes, struct EXTERNAL_GFX_OP* gfx_op, Z_ORDER_LEVEL max_zorder = Z_ORDER_LEVEL_0, c_rect overlpa_rect = c_rect()) : c_surface(width, height, color_bytes, max_zorder, overlpa_rect), m_gfx_op(gfx_op) {} -protected: - virtual void fill_rect_on_fb(int x0, int y0, int x1, int y1, unsigned int rgb) - { - if (!m_gfx_op) - { - return; - } - if (m_gfx_op->fill_rect) - { - return m_gfx_op->fill_rect(x0, y0, x1, y1, rgb); - } - if (m_gfx_op->draw_pixel && m_is_active) - { - for (int y = y0; y <= y1; y++) - { - for (int x = x0; x <= x1; x++) - { - m_gfx_op->draw_pixel(x, y, rgb); - } - } - } - if (!m_fb) { return; } - if (m_color_bytes == 4) - { - unsigned int* fb; - for (int y = y0; y <= y1; y++) - { - fb = &((unsigned int*)m_fb)[y0 * m_width + x0]; - for (int x = x0; x <= x1; x++) - { - *fb++ = rgb; - } - } - } - else if (m_color_bytes == 2) - { - unsigned short* fb; - rgb = GL_RGB_32_to_16(rgb); - for (int y = y0; y <= y1; y++) - { - fb = &((unsigned short*)m_fb)[y0 * m_width + x0]; - for (int x = x0; x <= x1; x++) - { - *fb++ = rgb; - } - } - } - } - virtual void draw_pixel_on_fb(int x, int y, unsigned int rgb) - { - if (m_gfx_op && m_gfx_op->draw_pixel && m_is_active) - { - m_gfx_op->draw_pixel(x, y, rgb); - } - if (!m_fb) { return; } - if (m_color_bytes == 4) - { - ((unsigned int*)m_fb)[y * m_width + x] = rgb; - } - else if (m_color_bytes == 2) - { - ((unsigned short*)m_fb)[y * m_width + x] = GL_RGB_32_to_16(rgb); - } - } - struct EXTERNAL_GFX_OP* m_gfx_op;//Rendering by external method -}; -inline c_display::c_display(void* phy_fb, int display_width, int display_height, int surface_width, int surface_height, unsigned int color_bytes, int surface_cnt, EXTERNAL_GFX_OP* gfx_op) : m_width(display_width), m_height(display_height), m_color_bytes(color_bytes), m_phy_fb(phy_fb), m_phy_read_index(0), m_phy_write_index(0), m_surface_cnt(surface_cnt), m_surface_index(0) -{ - ASSERT(color_bytes == 2 || color_bytes == 4); - ASSERT(m_surface_cnt <= SURFACE_CNT_MAX); - memset(m_surface_group, 0, sizeof(m_surface_group)); - - for (int i = 0; i < m_surface_cnt; i++) - { - m_surface_group[i] = (phy_fb) ? new c_surface(surface_width, surface_height, color_bytes) : new c_surface_no_fb(surface_width, surface_height, color_bytes, gfx_op); - m_surface_group[i]->attach_display(this); - } -} -inline c_display::c_display(void* phy_fb, int display_width, int display_height, c_surface* surface) : m_width(display_width), m_height(display_height), m_phy_fb(phy_fb), m_phy_read_index(0), m_phy_write_index(0), m_surface_cnt(1), m_surface_index(0) -{ - m_color_bytes = surface->m_color_bytes; - surface->m_is_active = true; - (m_surface_group[0] = surface)->attach_display(this); -} -inline c_surface* c_display::alloc_surface(Z_ORDER_LEVEL max_zorder, c_rect layer_rect) -{ - ASSERT(max_zorder < Z_ORDER_LEVEL_MAX && m_surface_index < m_surface_cnt); - (layer_rect == c_rect()) ? m_surface_group[m_surface_index]->set_surface(max_zorder, c_rect(0, 0, m_width - 1, m_height - 1)) : m_surface_group[m_surface_index]->set_surface(max_zorder, layer_rect); - return m_surface_group[m_surface_index++]; -} -inline int c_display::swipe_surface(c_surface* s0, c_surface* s1, int x0, int x1, int y0, int y1, int offset) -{ - int surface_width = s0->get_width(); - int surface_height = s0->get_height(); - if (offset < 0 || offset > surface_width || y0 < 0 || y0 >= surface_height || - y1 < 0 || y1 >= surface_height || x0 < 0 || x0 >= surface_width || x1 < 0 || x1 >= surface_width) - { - ASSERT(false); - return -1; - } - int width = (x1 - x0 + 1); - if (width < 0 || width > surface_width || width < offset) - { - ASSERT(false); - return -1; - } - x0 = (x0 >= m_width) ? (m_width - 1) : x0; - x1 = (x1 >= m_width) ? (m_width - 1) : x1; - y0 = (y0 >= m_height) ? (m_height - 1) : y0; - y1 = (y1 >= m_height) ? (m_height - 1) : y1; - if (m_phy_fb) - { - for (int y = y0; y <= y1; y++) - { - //Left surface - char* addr_s = ((char*)(s0->m_fb) + (y * (s0->get_width()) + x0 + offset) * m_color_bytes); - char* addr_d = ((char*)(m_phy_fb)+(y * m_width + x0) * m_color_bytes); - memcpy(addr_d, addr_s, (width - offset) * m_color_bytes); - //Right surface - addr_s = ((char*)(s1->m_fb) + (y * (s1->get_width()) + x0) * m_color_bytes); - addr_d = ((char*)(m_phy_fb)+(y * m_width + x0 + (width - offset)) * m_color_bytes); - memcpy(addr_d, addr_s, offset * m_color_bytes); - } - } - else if (m_color_bytes == 4) - { - void(*draw_pixel)(int x, int y, unsigned int rgb) = ((c_surface_no_fb*)s0)->m_gfx_op->draw_pixel; - for (int y = y0; y <= y1; y++) - { - //Left surface - for (int x = x0; x <= (x1 - offset); x++) - { - draw_pixel(x, y, ((unsigned int*)s0->m_fb)[y * m_width + x + offset]); - } - //Right surface - for (int x = x1 - offset; x <= x1; x++) - { - draw_pixel(x, y, ((unsigned int*)s1->m_fb)[y * m_width + x + offset - x1 + x0]); - } - } - } - else if (m_color_bytes == 2) - { - void(*draw_pixel)(int x, int y, unsigned int rgb) = ((c_surface_no_fb*)s0)->m_gfx_op->draw_pixel; - for (int y = y0; y <= y1; y++) - { - //Left surface - for (int x = x0; x <= (x1 - offset); x++) - { - draw_pixel(x, y, GL_RGB_16_to_32(((unsigned short*)s0->m_fb)[y * m_width + x + offset])); - } - //Right surface - for (int x = x1 - offset; x <= x1; x++) - { - draw_pixel(x, y, GL_RGB_16_to_32(((unsigned short*)s1->m_fb)[y * m_width + x + offset - x1 + x0])); - } - } - } - m_phy_write_index++; - return 0; -} -#include -#include -#define VALUE_STR_LEN 16 -class c_surface; -class c_font_operator -{ -public: - virtual void draw_string(c_surface* surface, int z_order, const void* string, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) = 0; - virtual void draw_string_in_rect(c_surface* surface, int z_order, const void* string, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) = 0; - virtual void draw_value(c_surface* surface, int z_order, int value, int dot_position, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) = 0; - virtual void draw_value_in_rect(c_surface* surface, int z_order, int value, int dot_position, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) = 0; - virtual int get_str_size(const void* string, const void* font, int& width, int& height) = 0; - void get_string_pos(const void* string, const void* font, c_rect rect, unsigned int align_type, int& x, int& y) - { - int x_size, y_size; - get_str_size(string, font, x_size, y_size); - int height = rect.m_bottom - rect.m_top + 1; - int width = rect.m_right - rect.m_left + 1; - x = y = 0; - switch (align_type & ALIGN_HMASK) - { - case ALIGN_HCENTER: - //m_text_org_x=0 - if (width > x_size) - { - x = (width - x_size) / 2; - } - break; - case ALIGN_LEFT: - x = 0; - break; - case ALIGN_RIGHT: - //m_text_org_x=0 - if (width > x_size) - { - x = width - x_size; - } - break; - default: - ASSERT(0); - break; - } - switch (align_type & ALIGN_VMASK) - { - case ALIGN_VCENTER: - //m_text_org_y=0 - if (height > y_size) - { - y = (height - y_size) / 2; - } - break; - case ALIGN_TOP: - y = 0; - break; - case ALIGN_BOTTOM: - //m_text_org_y=0 - if (height > y_size) - { - y = height - y_size; - } - break; - default: - ASSERT(0); - break; - } - } -}; -class c_lattice_font_op : public c_font_operator -{ -public: - void draw_string(c_surface* surface, int z_order, const void* string, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) - { - const char* s = (const char*)string; - if (0 == s) - { - return; - } - int offset = 0; - unsigned int utf8_code; - while (*s) - { - s += get_utf8_code(s, utf8_code); - offset += draw_single_char(surface, z_order, utf8_code, (x + offset), y, (const LATTICE_FONT_INFO*)font, font_color, bg_color); - } - } - void draw_string_in_rect(c_surface* surface, int z_order, const void* string, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) - { - const char* s = (const char*)string; - if (0 == s) - { - return; - } - int x, y; - get_string_pos(s, (const LATTICE_FONT_INFO*)font, rect, align_type, x, y); - draw_string(surface, z_order, string, rect.m_left + x, rect.m_top + y, font, font_color, bg_color); - } - void draw_value(c_surface* surface, int z_order, int value, int dot_position, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) - { - char buf[VALUE_STR_LEN]; - value_2_string(value, dot_position, buf, VALUE_STR_LEN); - draw_string(surface, z_order, buf, x, y, (const LATTICE_FONT_INFO*)font, font_color, bg_color); - } - void draw_value_in_rect(c_surface* surface, int z_order, int value, int dot_position, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) - { - char buf[VALUE_STR_LEN]; - value_2_string(value, dot_position, buf, VALUE_STR_LEN); - draw_string_in_rect(surface, z_order, buf, rect, (const LATTICE_FONT_INFO*)font, font_color, bg_color, align_type); - } - int get_str_size(const void *string, const void* font, int& width, int& height) - { - const char* s = (const char*)string; - if (0 == s || 0 == font) - { - width = height = 0; - return -1; - } - int lattice_width = 0; - unsigned int utf8_code; - int utf8_bytes; - while (*s) - { - utf8_bytes = get_utf8_code(s, utf8_code); - const LATTICE* p_lattice = get_lattice((const LATTICE_FONT_INFO*)font, utf8_code); - lattice_width += p_lattice ? p_lattice->width : ((const LATTICE_FONT_INFO*)font)->height; - s += utf8_bytes; - } - width = lattice_width; - height = ((const LATTICE_FONT_INFO*)font)->height; - return 0; - } -private: - void value_2_string(int value, int dot_position, char* buf, int len) - { - memset(buf, 0, len); - switch (dot_position) - { - case 0: - sprintf(buf, "%d", value); - break; - case 1: - sprintf(buf, "%.1f", value * 1.0 / 10); - break; - case 2: - sprintf(buf, "%.2f", value * 1.0 / 100); - break; - case 3: - sprintf(buf, "%.3f", value * 1.0 / 1000); - break; - default: - ASSERT(false); - break; - } - } - int draw_single_char(c_surface* surface, int z_order, unsigned int utf8_code, int x, int y, const LATTICE_FONT_INFO* font, unsigned int font_color, unsigned int bg_color) - { - unsigned int error_color = 0xFFFFFFFF; - if (font) - { - const LATTICE* p_lattice = get_lattice(font, utf8_code); - if (p_lattice) - { - draw_lattice(surface, z_order, x, y, p_lattice->width, font->height, p_lattice->pixel_buffer, font_color, bg_color); - return p_lattice->width; - } - } - else - { - error_color = GL_RGB(255, 0, 0); - } - //lattice/font not found, draw "X" - int len = 16; - for (int y_ = 0; y_ < len; y_++) - { - for (int x_ = 0; x_ < len; x_++) - { - int diff = (x_ - y_); - int sum = (x_ + y_); - (diff == 0 || diff == -1 || diff == 1 || sum == len || sum == (len - 1) || sum == (len + 1)) ? - surface->draw_pixel((x + x_), (y + y_), error_color, z_order) : surface->draw_pixel((x + x_), (y + y_), 0, z_order); - } - } - return len; - } - void draw_lattice(c_surface* surface, int z_order, int x, int y, int width, int height, const unsigned char* p_data, unsigned int font_color, unsigned int bg_color) - { - unsigned int r, g, b, rgb; - unsigned char blk_value = *p_data++; - unsigned char blk_cnt = *p_data++; - b = (GL_RGB_B(font_color) * blk_value + GL_RGB_B(bg_color) * (255 - blk_value)) >> 8; - g = (GL_RGB_G(font_color) * blk_value + GL_RGB_G(bg_color) * (255 - blk_value)) >> 8; - r = (GL_RGB_R(font_color) * blk_value + GL_RGB_R(bg_color) * (255 - blk_value)) >> 8; - rgb = GL_RGB(r, g, b); - for (int y_ = 0; y_ < height; y_++) - { - for (int x_ = 0; x_ < width; x_++) - { - ASSERT(blk_cnt); - if (0x00 == blk_value) - { - if (GL_ARGB_A(bg_color)) - { - surface->draw_pixel(x + x_, y + y_, bg_color, z_order); - } - } - else - { - surface->draw_pixel((x + x_), (y + y_), rgb, z_order); - } - if (--blk_cnt == 0) - {//reload new block - blk_value = *p_data++; - blk_cnt = *p_data++; - b = (GL_RGB_B(font_color) * blk_value + GL_RGB_B(bg_color) * (255 - blk_value)) >> 8; - g = (GL_RGB_G(font_color) * blk_value + GL_RGB_G(bg_color) * (255 - blk_value)) >> 8; - r = (GL_RGB_R(font_color) * blk_value + GL_RGB_R(bg_color) * (255 - blk_value)) >> 8; - rgb = GL_RGB(r, g, b); - } - } - } - } - - const LATTICE* get_lattice(const LATTICE_FONT_INFO* font, unsigned int utf8_code) - { - int first = 0; - int last = font->count - 1; - int middle = (first + last) / 2; - while (first <= last) - { - if (font->lattice_array[middle].utf8_code < utf8_code) - first = middle + 1; - else if (font->lattice_array[middle].utf8_code == utf8_code) - { - return &font->lattice_array[middle]; - } - else - { - last = middle - 1; - } - middle = (first + last) / 2; - } - return 0; - } - - static int get_utf8_code(const char* s, unsigned int& output_utf8_code) - { - static unsigned char s_utf8_length_table[256] = - { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1 - }; - unsigned char* us = (unsigned char*)s; - int utf8_bytes = s_utf8_length_table[*us]; - switch (utf8_bytes) - { - case 1: - output_utf8_code = *us; - break; - case 2: - output_utf8_code = (*us << 8) | (*(us + 1)); - break; - case 3: - output_utf8_code = (*us << 16) | ((*(us + 1)) << 8) | *(us + 2); - break; - case 4: - output_utf8_code = (*us << 24) | ((*(us + 1)) << 16) | (*(us + 2) << 8) | *(us + 3); - break; - default: - ASSERT(false); - break; - } - return utf8_bytes; - } -}; -class c_word -{ -public: - static void draw_string(c_surface* surface, int z_order, const void* string, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color)//string: char or wchar_t - { - fontOperator->draw_string(surface, z_order, string, x, y, font, font_color, bg_color); - } - static void draw_string_in_rect(c_surface* surface, int z_order, const void* string, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT)//string: char or wchar_t - { - fontOperator->draw_string_in_rect(surface, z_order, string, rect, font, font_color, bg_color, align_type); - } - static void draw_value_in_rect(c_surface* surface, int z_order, int value, int dot_position, c_rect rect, const void* font, unsigned int font_color, unsigned int bg_color, unsigned int align_type = ALIGN_LEFT) - { - fontOperator->draw_value_in_rect(surface, z_order, value, dot_position, rect, font, font_color, bg_color, align_type); - } - static void draw_value(c_surface* surface, int z_order, int value, int dot_position, int x, int y, const void* font, unsigned int font_color, unsigned int bg_color) - { - fontOperator->draw_value(surface, z_order, value, dot_position, x, y, font, font_color, bg_color); - } - - static int get_str_size(const void* string, const void* font, int& width, int& height) - { - return fontOperator->get_str_size(string, font, width, height); - } - static c_font_operator* fontOperator; -}; -#define DEFAULT_MASK_COLOR 0xFF080408 -class c_surface; -class c_image_operator -{ -public: - virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, unsigned int mask_rgb = DEFAULT_MASK_COLOR) = 0; - virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, int src_x, int src_y, int width, int height, unsigned int mask_rgb = DEFAULT_MASK_COLOR) = 0; -}; -class c_bitmap_operator : public c_image_operator -{ -public: - virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, unsigned int mask_rgb = DEFAULT_MASK_COLOR) - { - ASSERT(image_info); - BITMAP_INFO* pBitmap = (BITMAP_INFO*)image_info; - unsigned short* lower_fb_16 = 0; - unsigned int* lower_fb_32 = 0; - int lower_fb_width = 0; - c_rect lower_fb_rect; - if (z_order >= Z_ORDER_LEVEL_1) - { - lower_fb_16 = (unsigned short*)surface->m_layers[z_order - 1].fb; - lower_fb_32 = (unsigned int*)surface->m_layers[z_order - 1].fb; - lower_fb_rect = surface->m_layers[z_order - 1].rect; - lower_fb_width = lower_fb_rect.width(); - } - unsigned int mask_rgb_16 = GL_RGB_32_to_16(mask_rgb); - int xsize = pBitmap->width; - int ysize = pBitmap->height; - const unsigned short* pData = (const unsigned short*)pBitmap->pixel_color_array; - int color_bytes = surface->m_color_bytes; - for (int y_ = y; y_ < y + ysize; y_++) - { - for (int x_ = x; x_ < x + xsize; x_++) - { - unsigned int rgb = *pData++; - if (mask_rgb_16 == rgb) - { - if (lower_fb_rect.pt_in_rect(x_, y_)) - {//show lower layer - surface->draw_pixel(x_, y_, (color_bytes == 4) ? lower_fb_32[(y_ - lower_fb_rect.m_top) * lower_fb_width + (x_ - lower_fb_rect.m_left)] : GL_RGB_16_to_32(lower_fb_16[(y_ - lower_fb_rect.m_top) * lower_fb_width + (x_ - lower_fb_rect.m_left)]), z_order); - } - } - else - { - surface->draw_pixel(x_, y_, GL_RGB_16_to_32(rgb), z_order); - } - } - } - } - virtual void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, int src_x, int src_y, int width, int height, unsigned int mask_rgb = DEFAULT_MASK_COLOR) - { - ASSERT(image_info); - BITMAP_INFO* pBitmap = (BITMAP_INFO*)image_info; - if (0 == pBitmap || (src_x + width > pBitmap->width) || (src_y + height > pBitmap->height)) - { - return; - } - unsigned short* lower_fb_16 = 0; - unsigned int* lower_fb_32 = 0; - int lower_fb_width = 0; - c_rect lower_fb_rect; - if (z_order >= Z_ORDER_LEVEL_1) - { - lower_fb_16 = (unsigned short*)surface->m_layers[z_order - 1].fb; - lower_fb_32 = (unsigned int*)surface->m_layers[z_order - 1].fb; - lower_fb_rect = surface->m_layers[z_order - 1].rect; - lower_fb_width = lower_fb_rect.width(); - } - unsigned int mask_rgb_16 = GL_RGB_32_to_16(mask_rgb); - const unsigned short* pData = (const unsigned short*)pBitmap->pixel_color_array; - int color_bytes = surface->m_color_bytes; - for (int y_ = 0; y_ < height; y_++) - { - const unsigned short* p = &pData[src_x + (src_y + y_) * pBitmap->width]; - for (int x_ = 0; x_ < width; x_++) - { - unsigned int rgb = *p++; - if (mask_rgb_16 == rgb) - { - if (lower_fb_rect.pt_in_rect(x + x_, y + y_)) - {//show lower layer - surface->draw_pixel(x + x_, y + y_, (color_bytes == 4) ? lower_fb_32[(y + y_ - lower_fb_rect.m_top) * lower_fb_width + x + x_ - lower_fb_rect.m_left] : GL_RGB_16_to_32(lower_fb_16[(y + y_ - lower_fb_rect.m_top) * lower_fb_width + x + x_ - lower_fb_rect.m_left]), z_order); - } - } - else - { - surface->draw_pixel(x + x_, y + y_, GL_RGB_16_to_32(rgb), z_order); - } - } - } - } -}; -class c_image -{ -public: - static void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, unsigned int mask_rgb = DEFAULT_MASK_COLOR) - { - image_operator->draw_image(surface, z_order, image_info, x, y, mask_rgb); - } - static void draw_image(c_surface* surface, int z_order, const void* image_info, int x, int y, int src_x, int src_y, int width, int height, unsigned int mask_rgb = DEFAULT_MASK_COLOR) - { - image_operator->draw_image(surface, z_order, image_info, x, y, src_x, src_y, width, height, mask_rgb); - } - - static c_image_operator* image_operator; -}; -class c_wnd; -class c_surface; -typedef enum -{ - ATTR_VISIBLE = 0x40000000L, - ATTR_FOCUS = 0x20000000L, - ATTR_PRIORITY = 0x10000000L// Handle touch action at high priority -}WND_ATTRIBUTION; -typedef enum -{ - STATUS_NORMAL, - STATUS_PUSHED, - STATUS_FOCUSED, - STATUS_DISABLED -}WND_STATUS; -typedef enum -{ - NAV_FORWARD, - NAV_BACKWARD, - NAV_ENTER -}NAVIGATION_KEY; -typedef enum -{ - TOUCH_DOWN, - TOUCH_UP -}TOUCH_ACTION; -typedef struct struct_wnd_tree -{ - c_wnd* p_wnd;//window instance - unsigned int resource_id;//ID - const char* str;//caption - short x;//position x - short y;//position y - short width; - short height; - struct struct_wnd_tree* p_child_tree;//sub tree -}WND_TREE; -typedef void (c_wnd::*WND_CALLBACK)(int, int); -class c_wnd -{ -public: - c_wnd() : m_status(STATUS_NORMAL), m_attr((WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS)), m_parent(0), m_top_child(0), m_prev_sibling(0), m_next_sibling(0), - m_str(0), m_font_color(0), m_bg_color(0), m_id(0), m_z_order(Z_ORDER_LEVEL_0), m_focus_child(0), m_surface(0) {}; - virtual ~c_wnd() {}; - virtual int connect(c_wnd *parent, unsigned short resource_id, const char* str, - short x, short y, short width, short height, WND_TREE* p_child_tree = 0) - { - if (0 == resource_id) - { - ASSERT(false); - return -1; - } - m_id = resource_id; - set_str(str); - m_parent = parent; - m_status = STATUS_NORMAL; - if (parent) - { - m_z_order = parent->m_z_order; - m_surface = parent->m_surface; - } - if (0 == m_surface) - { - ASSERT(false); - return -2; - } - /* (cs.x = x * 1024 / 768) for 1027*768=>800*600 quickly*/ - m_wnd_rect.m_left = x; - m_wnd_rect.m_top = y; - m_wnd_rect.m_right = (x + width - 1); - m_wnd_rect.m_bottom = (y + height - 1); - pre_create_wnd(); - if (0 != parent) - { - parent->add_child_2_tail(this); - } - if (load_child_wnd(p_child_tree) >= 0) - { - on_init_children(); - } - return 0; - } - void disconnect() - { - if (0 == m_id) - { - return; - } - if (0 != m_top_child) - { - c_wnd* child = m_top_child; - c_wnd* next_child = 0; - while (child) - { - next_child = child->m_next_sibling; - child->disconnect(); - child = next_child; - } - } - if (0 != m_parent) - { - m_parent->unlink_child(this); - } - m_focus_child = 0; - m_id = 0; - } - virtual void on_init_children() {} - virtual void on_paint() {} - virtual void show_window() - { - if (ATTR_VISIBLE == (m_attr & ATTR_VISIBLE)) - { - on_paint(); - c_wnd* child = m_top_child; - if (0 != child) - { - while (child) - { - child->show_window(); - child = child->m_next_sibling; - } - } - } - } - unsigned short get_id() const { return m_id; } - int get_z_order() { return m_z_order; } - c_wnd* get_wnd_ptr(unsigned short id) const - { - c_wnd* child = m_top_child; - while (child) - { - if (child->get_id() == id) - { - break; - } - child = child->m_next_sibling; - } - return child; - } - unsigned int get_attr() const { return m_attr; } - void set_str(const char* str) { m_str = str; } - void set_attr(WND_ATTRIBUTION attr) { m_attr = attr; } - bool is_focus_wnd() const - { - return ((m_attr & ATTR_VISIBLE) && (m_attr & ATTR_FOCUS)) ? true : false; - } - void set_font_color(unsigned int color) { m_font_color = color; } - unsigned int get_font_color() { return m_font_color; } - void set_bg_color(unsigned int color) { m_bg_color = color; } - unsigned int get_bg_color() { return m_bg_color; } - void set_font_type(const LATTICE_FONT_INFO *font_type) { m_font = font_type; } - const void* get_font_type() { return m_font; } - void set_wnd_pos(short x, short y, short width, short height) - { - m_wnd_rect.m_left = x; - m_wnd_rect.m_top = y; - m_wnd_rect.m_right = x + width - 1; - m_wnd_rect.m_bottom = y + height - 1; - } - void get_wnd_rect(c_rect &rect) const { rect = m_wnd_rect; } - void get_screen_rect(c_rect &rect) const - { - int l = 0; - int t = 0; - wnd2screen(l, t); - rect.set_rect(l, t, m_wnd_rect.width(), m_wnd_rect.height()); - } - c_wnd* set_child_focus(c_wnd *focus_child) - { - ASSERT(0 != focus_child); - ASSERT(focus_child->m_parent == this); - c_wnd* old_focus_child = m_focus_child; - if (focus_child->is_focus_wnd()) - { - if (focus_child != old_focus_child) - { - if (old_focus_child) - { - old_focus_child->on_kill_focus(); - } - m_focus_child = focus_child; - m_focus_child->on_focus(); - } - } - return m_focus_child; - } - c_wnd* get_parent() const { return m_parent; } - c_wnd* get_last_child() const - { - if (0 == m_top_child) - { - return 0; - } - c_wnd* child = m_top_child; - while (child->m_next_sibling) - { - child = child->m_next_sibling; - } - return child; - } - int unlink_child(c_wnd *child) - { - if ((0 == child) - || (this != child->m_parent)) - { - return -1; - } - if (0 == m_top_child) - { - return -2; - } - bool find = false; - c_wnd* tmp_child = m_top_child; - if (tmp_child == child) - { - m_top_child = child->m_next_sibling; - if (0 != child->m_next_sibling) - { - child->m_next_sibling->m_prev_sibling = 0; - } - find = true; - } - else - { - while (tmp_child->m_next_sibling) - { - if (child == tmp_child->m_next_sibling) - { - tmp_child->m_next_sibling = child->m_next_sibling; - if (0 != child->m_next_sibling) - { - child->m_next_sibling->m_prev_sibling = tmp_child; - } - find = true; - break; - } - tmp_child = tmp_child->m_next_sibling; - } - } - if (true == find) - { - if (m_focus_child == child) - { - m_focus_child = 0; - } - child->m_next_sibling = 0; - child->m_prev_sibling = 0; - return 1; - } - else - { - return 0; - } - } - c_wnd* get_prev_sibling() const { return m_prev_sibling; } - c_wnd* get_next_sibling() const { return m_next_sibling; } - virtual void on_touch(int x, int y, TOUCH_ACTION action) - { - x -= m_wnd_rect.m_left; - y -= m_wnd_rect.m_top; - c_wnd* priority_wnd = 0; - c_wnd* tmp_child = m_top_child; - while (tmp_child) - { - if ((tmp_child->m_attr & ATTR_PRIORITY) && (tmp_child->m_attr & ATTR_VISIBLE)) - { - priority_wnd = tmp_child; - break; - } - tmp_child = tmp_child->m_next_sibling; - } - if (priority_wnd) - { - return priority_wnd->on_touch(x, y, action); - } - c_wnd* child = m_top_child; - while (child) - { - if (child->is_focus_wnd()) - { - c_rect rect; - child->get_wnd_rect(rect); - if (true == rect.pt_in_rect(x, y)) - { - return child->on_touch(x, y, action); - } - } - child = child->m_next_sibling; - } - } - virtual void on_navigate(NAVIGATION_KEY key) - { - c_wnd* priority_wnd = 0; - c_wnd* tmp_child = m_top_child; - while (tmp_child) - { - if ((tmp_child->m_attr & ATTR_PRIORITY) && (tmp_child->m_attr & ATTR_VISIBLE)) - { - priority_wnd = tmp_child; - break; - } - tmp_child = tmp_child->m_next_sibling; - } - if (priority_wnd) - { - return priority_wnd->on_navigate(key); - } - if (!is_focus_wnd()) - { - return; - } - if (key != NAV_BACKWARD && key != NAV_FORWARD) - { - if (m_focus_child) - { - m_focus_child->on_navigate(key); - } - return; - } - // Move focus - c_wnd* old_focus_wnd = m_focus_child; - // No current focus wnd, new one. - if (!old_focus_wnd) - { - c_wnd* child = m_top_child; - c_wnd* new_focus_wnd = 0; - while (child) - { - if (child->is_focus_wnd()) - { - new_focus_wnd = child; - new_focus_wnd->m_parent->set_child_focus(new_focus_wnd); - child = child->m_top_child; - continue; - } - child = child->m_next_sibling; - } - return; - } - // Move focus from old wnd to next wnd - c_wnd* next_focus_wnd = (key == NAV_FORWARD) ? old_focus_wnd->m_next_sibling : old_focus_wnd->m_prev_sibling; - while (next_focus_wnd && (!next_focus_wnd->is_focus_wnd())) - {// Search neighbor of old focus wnd - next_focus_wnd = (key == NAV_FORWARD) ? next_focus_wnd->m_next_sibling : next_focus_wnd->m_prev_sibling; - } - if (!next_focus_wnd) - {// Search whole brother wnd - next_focus_wnd = (key == NAV_FORWARD) ? old_focus_wnd->m_parent->m_top_child : old_focus_wnd->m_parent->get_last_child(); - while (next_focus_wnd && (!next_focus_wnd->is_focus_wnd())) - { - next_focus_wnd = (key == NAV_FORWARD) ? next_focus_wnd->m_next_sibling : next_focus_wnd->m_prev_sibling; - } - } - if (next_focus_wnd) - { - next_focus_wnd->m_parent->set_child_focus(next_focus_wnd); - } - } - c_surface* get_surface() { return m_surface; } - void set_surface(c_surface* surface) { m_surface = surface; } -protected: - virtual void pre_create_wnd() {}; - void add_child_2_tail(c_wnd *child) - { - if (0 == child)return; - if (child == get_wnd_ptr(child->m_id))return; - if (0 == m_top_child) - { - m_top_child = child; - child->m_prev_sibling = 0; - child->m_next_sibling = 0; - } - else - { - c_wnd* last_child = get_last_child(); - if (0 == last_child) - { - ASSERT(false); - } - last_child->m_next_sibling = child; - child->m_prev_sibling = last_child; - child->m_next_sibling = 0; - } - } - void wnd2screen(int &x, int &y) const - { - c_wnd* parent = m_parent; - c_rect rect; - x += m_wnd_rect.m_left; - y += m_wnd_rect.m_top; - while (0 != parent) - { - parent->get_wnd_rect(rect); - x += rect.m_left; - y += rect.m_top; - parent = parent->m_parent; - } - } - int load_child_wnd(WND_TREE *p_child_tree) - { - if (0 == p_child_tree) - { - return 0; - } - int sum = 0; - WND_TREE* p_cur = p_child_tree; - while (p_cur->p_wnd) - { - if (0 != p_cur->p_wnd->m_id) - {//This wnd has been used! Do not share! - ASSERT(false); - return -1; - } - else - { - p_cur->p_wnd->connect(this, p_cur->resource_id, p_cur->str, - p_cur->x, p_cur->y, p_cur->width, p_cur->height, p_cur->p_child_tree); - } - p_cur++; - sum++; - } - return sum; - } - void set_active_child(c_wnd* child) { m_focus_child = child; } - virtual void on_focus() {}; - virtual void on_kill_focus() {}; -protected: - unsigned short m_id; - WND_STATUS m_status; - WND_ATTRIBUTION m_attr; - c_rect m_wnd_rect; //position relative to parent window. - c_wnd* m_parent; //parent window - c_wnd* m_top_child; //the first sub window would be navigated - c_wnd* m_prev_sibling; //previous brother - c_wnd* m_next_sibling; //next brother - c_wnd* m_focus_child; //current focused window - const char* m_str; //caption - const void* m_font; //font face - unsigned int m_font_color; - unsigned int m_bg_color; - int m_z_order; //the graphic level for rendering - c_surface* m_surface; -}; -class c_button : public c_wnd -{ -public: - void set_on_click(WND_CALLBACK on_click) { this->on_click = on_click; } -protected: - virtual void on_paint() - { - c_rect rect; - get_screen_rect(rect); - switch (m_status) - { - case STATUS_NORMAL: - m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); - if (m_str) - { - c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); - } - break; - case STATUS_FOCUSED: - m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); - if (m_str) - { - c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); - } - break; - case STATUS_PUSHED: - m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_PUSHED), m_z_order); - m_surface->draw_rect(rect, c_theme::get_color(COLOR_WND_BORDER), 2, m_z_order); - if (m_str) - { - c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_PUSHED), ALIGN_HCENTER | ALIGN_VCENTER); - } - break; - default: - ASSERT(false); - break; - } - } - virtual void on_focus() - { - m_status = STATUS_FOCUSED; - on_paint(); - } - virtual void on_kill_focus() - { - m_status = STATUS_NORMAL; - on_paint(); - } - virtual void pre_create_wnd() - { - on_click = 0; - m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); - m_font = c_theme::get_font(FONT_DEFAULT); - m_font_color = c_theme::get_color(COLOR_WND_FONT); - } - virtual void on_touch(int x, int y, TOUCH_ACTION action) - { - if (action == TOUCH_DOWN) - { - m_parent->set_child_focus(this); - m_status = STATUS_PUSHED; - on_paint(); - } - else - { - m_status = STATUS_FOCUSED; - on_paint(); - if(on_click) - { - (m_parent->*(on_click))(m_id, 0); - } - } - } - virtual void on_navigate(NAVIGATION_KEY key) - { - switch (key) - { - case NAV_ENTER: - on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_DOWN); - on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_UP); - break; - case NAV_FORWARD: - case NAV_BACKWARD: - break; - } - return c_wnd::on_navigate(key); - } - WND_CALLBACK on_click; -}; -class c_surface; -class c_dialog; -typedef struct -{ - c_dialog* dialog; - c_surface* surface; -} DIALOG_ARRAY; -class c_dialog : public c_wnd -{ -public: - static int open_dialog(c_dialog* p_dlg, bool modal_mode = true) - { - if (0 == p_dlg) - { - ASSERT(false); - return 0; - } - c_dialog* cur_dlg = get_the_dialog(p_dlg->get_surface()); - if (cur_dlg == p_dlg) - { - return 1; - } - if (cur_dlg) - { - cur_dlg->set_attr(WND_ATTRIBUTION(0)); - } - p_dlg->set_attr(modal_mode ? (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY) : (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS)); - p_dlg->show_window(); - p_dlg->set_me_the_dialog(); - return 1; - } - static int close_dialog(c_surface* surface) - { - c_dialog* dlg = get_the_dialog(surface); - if (0 == dlg) - { - return 0; - } - c_rect rc; - dlg->get_screen_rect(rc); - dlg->set_attr(WND_ATTRIBUTION(0)); - surface->show_layer(rc, dlg->m_z_order - 1); - //clear the dialog - for (int i = 0; i < SURFACE_CNT_MAX; i++) - { - if (ms_the_dialogs[i].surface == surface) - { - ms_the_dialogs[i].dialog = 0; - return 1; - } - } - ASSERT(false); - return -1; - } - static c_dialog* get_the_dialog(c_surface* surface) - { - for (int i = 0; i < SURFACE_CNT_MAX; i++) - { - if (ms_the_dialogs[i].surface == surface) - { - return ms_the_dialogs[i].dialog; - } - } - return 0; - } -protected: - virtual void pre_create_wnd() - { - m_attr = WND_ATTRIBUTION(0);// no focus/visible - m_z_order = Z_ORDER_LEVEL_1; - m_bg_color = GL_RGB(33, 42, 53); - } - virtual void on_paint() - { - c_rect rect; - get_screen_rect(rect); - m_surface->fill_rect(rect, m_bg_color, m_z_order); - if (m_str) - { - c_word::draw_string(m_surface, m_z_order, m_str, rect.m_left + 35, rect.m_top, c_theme::get_font(FONT_DEFAULT), GL_RGB(255, 255, 255), GL_ARGB(0, 0, 0, 0)); - } - } -private: - int set_me_the_dialog() - { - c_surface* surface = get_surface(); - for (int i = 0; i < SURFACE_CNT_MAX; i++) - { - if (ms_the_dialogs[i].surface == surface) - { - ms_the_dialogs[i].dialog = this; - return 0; - } - } - for (int i = 0; i < SURFACE_CNT_MAX; i++) - { - if (ms_the_dialogs[i].surface == 0) - { - ms_the_dialogs[i].dialog = this; - ms_the_dialogs[i].surface = surface; - return 1; - } - } - ASSERT(false); - return -2; - } - static DIALOG_ARRAY ms_the_dialogs[SURFACE_CNT_MAX]; -}; -#include -//Changing key width/height will change the width/height of keyboard -#define KEY_WIDTH 65 -#define KEY_HEIGHT 38 -#define KEYBOARD_WIDTH ((KEY_WIDTH + 2) * 10) -#define KEYBOARD_HEIGHT ((KEY_HEIGHT + 2) * 4) -#define NUM_BOARD_WIDTH ((KEY_WIDTH + 2) * 4) -#define NUM_BOARD_HEIGHT ((KEY_HEIGHT + 2) * 4) -#define CAPS_WIDTH (KEY_WIDTH * 3 / 2) -#define DEL_WIDTH (KEY_WIDTH * 3 / 2 + 1) -#define ESC_WIDTH (KEY_WIDTH * 2 + 2) -#define SWITCH_WIDTH (KEY_WIDTH * 3 / 2 ) -#define SPACE_WIDTH (KEY_WIDTH * 3 + 2 * 2) -#define DOT_WIDTH (KEY_WIDTH * 3 / 2 + 3) -#define ENTER_WIDTH (KEY_WIDTH * 2 + 2) -#define POS_X(c) ((KEY_WIDTH * c) + (c + 1) * 2) -#define POS_Y(r) ((KEY_HEIGHT * r) + (r + 1) * 2) -#define KEYBORAD_CLICK 0x5014 -#define ON_KEYBORAD_UPDATE(func) \ -{MSG_TYPE_WND, KEYBORAD_CLICK, 0, msgCallback(&func)}, -typedef enum -{ - STATUS_UPPERCASE, - STATUS_LOWERCASE -}KEYBOARD_STATUS; -typedef enum -{ - STYLE_ALL_BOARD, - STYLE_NUM_BOARD -}KEYBOARD_STYLE; -typedef enum -{ - CLICK_CHAR, - CLICK_ENTER, - CLICK_ESC -}CLICK_STATUS; -extern WND_TREE g_key_board_children[]; -extern WND_TREE g_number_board_children[]; -class c_keyboard: public c_wnd -{ -public: - virtual int connect(c_wnd *user, unsigned short resource_id, KEYBOARD_STYLE style) - { - c_rect user_rect; - user->get_wnd_rect(user_rect); - if (style == STYLE_ALL_BOARD) - {//Place keyboard at the bottom of user's parent window. - c_rect user_parent_rect; - user->get_parent()->get_wnd_rect(user_parent_rect); - return c_wnd::connect(user, resource_id, 0, (0 - user_rect.m_left), (user_parent_rect.height() - user_rect.m_top - KEYBOARD_HEIGHT - 1), KEYBOARD_WIDTH, KEYBOARD_HEIGHT, g_key_board_children); - } - else if (style == STYLE_NUM_BOARD) - {//Place keyboard below the user window. - return c_wnd::connect(user, resource_id, 0, 0, user_rect.height(), NUM_BOARD_WIDTH, NUM_BOARD_HEIGHT, g_number_board_children); - } - else - { - ASSERT(false); - } - return -1; - } - virtual void on_init_children() - { - c_wnd* child = m_top_child; - if (0 != child) - { - while (child) - { - ((c_button*)child)->set_on_click(WND_CALLBACK(&c_keyboard::on_key_clicked)); - child = child->get_next_sibling(); - } - } - } - KEYBOARD_STATUS get_cap_status(){return m_cap_status;} - char* get_str() { return m_str; } - void set_on_click(WND_CALLBACK on_click) { this->on_click = on_click; } -protected: - virtual void pre_create_wnd() - { - m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); - m_cap_status = STATUS_UPPERCASE; - memset(m_str, 0, sizeof(m_str)); - m_str_len = 0; - } - virtual void on_paint() - { - c_rect rect; - get_screen_rect(rect); - m_surface->fill_rect(rect, GL_RGB(0, 0, 0), m_z_order); - } - void on_key_clicked(int id, int param) - { - switch (id) - { - case 0x14: - on_caps_clicked(id, param); - break; - case '\n': - on_enter_clicked(id, param); - break; - case 0x1B: - on_esc_clicked(id, param); - break; - case 0x7F: - on_del_clicked(id, param); - break; - default: - on_char_clicked(id, param); - break; - } - } - void on_char_clicked(int id, int param) - {//id = char ascii code. - if (m_str_len >= sizeof(m_str)) - { - return; - } - if ((id >= '0' && id <= '9') || id == ' ' || id == '.') - { - goto InputChar; - } - if (id >= 'A' && id <= 'Z') - { - if (STATUS_LOWERCASE == m_cap_status) - { - id += 0x20; - } - goto InputChar; - } - ASSERT(false); - InputChar: - m_str[m_str_len++] = id; - (m_parent->*(on_click))(m_id, CLICK_CHAR); - } - void on_del_clicked(int id, int param) - { - if (m_str_len <= 0) - { - return; - } - m_str[--m_str_len] = 0; - (m_parent->*(on_click))(m_id, CLICK_CHAR); - } - void on_caps_clicked(int id, int param) - { - m_cap_status = (m_cap_status == STATUS_LOWERCASE) ? STATUS_UPPERCASE : STATUS_LOWERCASE; - show_window(); - } - void on_enter_clicked(int id, int param) - { - memset(m_str, 0, sizeof(m_str)); - (m_parent->*(on_click))(m_id, CLICK_ENTER); - } - void on_esc_clicked(int id, int param) - { - memset(m_str, 0, sizeof(m_str)); - (m_parent->*(on_click))(m_id, CLICK_ESC); - } -private: - char m_str[32]; - int m_str_len; - KEYBOARD_STATUS m_cap_status; - WND_CALLBACK on_click; -}; -class c_keyboard_button : public c_button -{ -protected: - virtual void on_paint() - { - c_rect rect; - get_screen_rect(rect); - switch (m_status) - { - case STATUS_NORMAL: - m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); - break; - case STATUS_FOCUSED: - m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); - break; - case STATUS_PUSHED: - m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_PUSHED), m_z_order); - m_surface->draw_rect(rect, c_theme::get_color(COLOR_WND_BORDER), 2, m_z_order); - break; - default: - ASSERT(false); - break; - } - if (m_id == 0x14) - { - return c_word::draw_string_in_rect(m_surface, m_z_order, "Caps", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); - } - else if (m_id == 0x1B) - { - return c_word::draw_string_in_rect(m_surface, m_z_order, "Esc", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); - } - else if (m_id == ' ') - { - return c_word::draw_string_in_rect(m_surface, m_z_order, "Space", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); - } - else if (m_id == '\n') - { - return c_word::draw_string_in_rect(m_surface, m_z_order, "Enter", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); - } - else if (m_id == '.') - { - return c_word::draw_string_in_rect(m_surface, m_z_order, ".", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); - } - else if (m_id == 0x7F) - { - return c_word::draw_string_in_rect(m_surface, m_z_order, "Back", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); - } - else if (m_id == 0x90) - { - return c_word::draw_string_in_rect(m_surface, m_z_order, "?123", rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); - } - char letter[] = { 0, 0 }; - if (m_id >= 'A' && m_id <= 'Z') - { - letter[0] = (((c_keyboard*)m_parent)->get_cap_status() == STATUS_UPPERCASE) ? m_id : (m_id + 0x20); - } - else if (m_id >= '0' && m_id <= '9') - { - letter[0] = (char)m_id; - } - c_word::draw_string_in_rect(m_surface, m_z_order, letter, rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_attr); - } -}; -#include -#define MAX_EDIT_STRLEN 32 -#define IDD_KEY_BOARD 0x1 -class c_edit : public c_wnd -{ - friend class c_keyboard; -public: - const char* get_text(){return m_str;} - void set_text(const char* str) - { - if (str != 0 && strlen(str) < sizeof(m_str)) - { - strcpy(m_str, str); - } - } - void set_keyboard_style(KEYBOARD_STYLE kb_sytle) { m_kb_style = kb_sytle; } - -protected: - virtual void pre_create_wnd() - { - m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); - m_kb_style = STYLE_ALL_BOARD; - m_font = c_theme::get_font(FONT_DEFAULT); - m_font_color = c_theme::get_color(COLOR_WND_FONT); - memset(m_str_input, 0, sizeof(m_str_input)); - memset(m_str, 0, sizeof(m_str)); - set_text(c_wnd::m_str); - } - virtual void on_paint() - { - c_rect rect, kb_rect; - get_screen_rect(rect); - s_keyboard.get_screen_rect(kb_rect); - switch (m_status) - { - case STATUS_NORMAL: - if (m_z_order > m_parent->get_z_order()) - { - s_keyboard.disconnect(); - m_z_order = m_parent->get_z_order(); - m_surface->show_layer(kb_rect, m_z_order); - m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); - } - m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); - c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); - break; - case STATUS_FOCUSED: - if (m_z_order > m_parent->get_z_order()) - { - s_keyboard.disconnect(); - m_z_order = m_parent->get_z_order(); - m_surface->show_layer(kb_rect, m_z_order); - m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); - } - m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); - c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); - break; - case STATUS_PUSHED: - if (m_z_order == m_parent->get_z_order()) - { - m_z_order++; - m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY); - show_keyboard(); - } - m_surface->fill_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, c_theme::get_color(COLOR_WND_PUSHED), m_parent->get_z_order()); - m_surface->draw_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, c_theme::get_color(COLOR_WND_BORDER), m_parent->get_z_order(), 2); - strlen(m_str_input) ? c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str_input, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_PUSHED), ALIGN_HCENTER | ALIGN_VCENTER) : - c_word::draw_string_in_rect(m_surface, m_parent->get_z_order(), m_str, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_PUSHED), ALIGN_HCENTER | ALIGN_VCENTER); - break; - default: - ASSERT(false); - } - } - virtual void on_focus() - { - m_status = STATUS_FOCUSED; - on_paint(); - } - virtual void on_kill_focus() - { - m_status = STATUS_NORMAL; - on_paint(); - } - virtual void on_navigate(NAVIGATION_KEY key) - { - switch (key) - { - case NAV_ENTER: - (m_status == STATUS_PUSHED) ? s_keyboard.on_navigate(key) : (on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_DOWN), on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_UP)); - return; - case NAV_BACKWARD: - case NAV_FORWARD: - return (m_status == STATUS_PUSHED) ? s_keyboard.on_navigate(key) : c_wnd::on_navigate(key); - } - } - virtual void on_touch(int x, int y, TOUCH_ACTION action) - { - (action == TOUCH_DOWN) ? on_touch_down(x, y) : on_touch_up(x, y); - } - void on_key_board_click(int id, int param) - { - switch (param) - { - case CLICK_CHAR: - strcpy(m_str_input, s_keyboard.get_str()); - on_paint(); - break; - case CLICK_ENTER: - if (strlen(m_str_input)) - { - memcpy(m_str, m_str_input, sizeof(m_str_input)); - } - m_status = STATUS_FOCUSED; - on_paint(); - break; - case CLICK_ESC: - memset(m_str_input, 0, sizeof(m_str_input)); - m_status = STATUS_FOCUSED; - on_paint(); - break; - default: - ASSERT(false); - break; - } - } -private: - void show_keyboard() - { - s_keyboard.connect(this, IDD_KEY_BOARD, m_kb_style); - s_keyboard.set_on_click(WND_CALLBACK(&c_edit::on_key_board_click)); - s_keyboard.show_window(); - } - void on_touch_down(int x, int y) - { - c_rect kb_rect_relate_2_edit_parent; - s_keyboard.get_wnd_rect(kb_rect_relate_2_edit_parent); - kb_rect_relate_2_edit_parent.m_left += m_wnd_rect.m_left; - kb_rect_relate_2_edit_parent.m_right += m_wnd_rect.m_left; - kb_rect_relate_2_edit_parent.m_top += m_wnd_rect.m_top; - kb_rect_relate_2_edit_parent.m_bottom += m_wnd_rect.m_top; - if (m_wnd_rect.pt_in_rect(x, y)) - {//click edit box - if (STATUS_NORMAL == m_status) - { - m_parent->set_child_focus(this); - } - } - else if (kb_rect_relate_2_edit_parent.pt_in_rect(x, y)) - {//click key board - c_wnd::on_touch(x, y, TOUCH_DOWN); - } - else - { - if (STATUS_PUSHED == m_status) - { - m_status = STATUS_FOCUSED; - on_paint(); - } - } - } - void on_touch_up(int x, int y) - { - if (STATUS_FOCUSED == m_status) - { - m_status = STATUS_PUSHED; - on_paint(); - } - else if (STATUS_PUSHED == m_status) - { - if (m_wnd_rect.pt_in_rect(x, y)) - {//click edit box - m_status = STATUS_FOCUSED; - on_paint(); - } - else - { - c_wnd::on_touch(x, y, TOUCH_UP); - } - } - } - static c_keyboard s_keyboard; - KEYBOARD_STYLE m_kb_style; - char m_str_input[MAX_EDIT_STRLEN]; - char m_str[MAX_EDIT_STRLEN]; -}; -class c_label : public c_wnd -{ -public: - virtual void on_paint() - { - c_rect rect; - unsigned int bg_color = m_bg_color ? m_bg_color : m_parent->get_bg_color(); - get_screen_rect(rect); - if (m_str) - { - m_surface->fill_rect(rect.m_left, rect.m_top, rect.m_right, rect.m_bottom, bg_color, m_z_order); - c_word::draw_string_in_rect(m_surface, m_z_order, m_str, rect, m_font, m_font_color, bg_color, ALIGN_LEFT | ALIGN_VCENTER); - } - } -protected: - virtual void pre_create_wnd() - { - m_attr = ATTR_VISIBLE; - m_font_color = c_theme::get_color(COLOR_WND_FONT); - m_font = c_theme::get_font(FONT_DEFAULT); - } -}; -#include -#define MAX_ITEM_NUM 4 -#define ITEM_HEIGHT 45 -class c_list_box : public c_wnd -{ -public: - void set_on_change(WND_CALLBACK on_change) { this->on_change = on_change; } - short get_item_count() { return m_item_total; } - int add_item(char* str) - { - if (m_item_total >= MAX_ITEM_NUM) - { - ASSERT(false); - return -1; - } - m_item_array[m_item_total++] = str; - update_list_size(); - return 0; - } - void clear_item() - { - m_selected_item = m_item_total = 0; - memset(m_item_array, 0, sizeof(m_item_array)); - update_list_size(); - } - void select_item(short index) - { - if (index < 0 || index >= m_item_total) - { - ASSERT(false); - } - m_selected_item = index; - } - -protected: - virtual void pre_create_wnd() - { - m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); - memset(m_item_array, 0, sizeof(m_item_array)); - m_item_total = 0; - m_selected_item = 0; - m_font = c_theme::get_font(FONT_DEFAULT); - m_font_color = c_theme::get_color(COLOR_WND_FONT); - } - virtual void on_paint() - { - c_rect rect; - get_screen_rect(rect); - switch (m_status) - { - case STATUS_NORMAL: - if (m_z_order > m_parent->get_z_order()) - { - m_z_order = m_parent->get_z_order(); - m_surface->show_layer(m_list_screen_rect, m_z_order); - m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); - } - m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); - c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[m_selected_item], rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); - break; - case STATUS_FOCUSED: - if (m_z_order > m_parent->get_z_order()) - { - m_z_order = m_parent->get_z_order(); - m_surface->show_layer(m_list_screen_rect, m_z_order); - m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS); - } - m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); - c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[m_selected_item], rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); - break; - case STATUS_PUSHED: - m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_PUSHED), m_z_order); - m_surface->draw_rect(rect, c_theme::get_color(COLOR_WND_BORDER), 2, m_z_order); - c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[m_selected_item], rect, m_font, GL_RGB(2, 124, 165), GL_ARGB(0, 0, 0, 0), ALIGN_HCENTER | ALIGN_VCENTER); - //draw list - if (m_item_total > 0) - { - if (m_z_order == m_parent->get_z_order()) - { - m_z_order++; - } - m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE | ATTR_FOCUS | ATTR_PRIORITY); - show_list(); - } - break; - default: - ASSERT(false); - } - } - virtual void on_focus() - { - m_status = STATUS_FOCUSED; - on_paint(); - } - virtual void on_kill_focus() - { - m_status = STATUS_NORMAL; - on_paint(); - } - virtual void on_navigate(NAVIGATION_KEY key) - { - switch (key) - { - case NAV_ENTER: - on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_DOWN); - on_touch(m_wnd_rect.m_left, m_wnd_rect.m_top, TOUCH_UP); - return; - case NAV_BACKWARD: - if (m_status != STATUS_PUSHED) - { - return c_wnd::on_navigate(key); - } - m_selected_item = (m_selected_item > 0) ? (m_selected_item - 1) : m_selected_item; - return show_list(); - case NAV_FORWARD: - if (m_status != STATUS_PUSHED) - { - return c_wnd::on_navigate(key); - } - m_selected_item = (m_selected_item < (m_item_total - 1)) ? (m_selected_item + 1) : m_selected_item; - return show_list(); - } - } - virtual void on_touch(int x, int y, TOUCH_ACTION action) - { - (action == TOUCH_DOWN) ? on_touch_down(x, y) : on_touch_up(x, y); - } - -private: - void update_list_size() - { - m_list_wnd_rect = m_wnd_rect; - m_list_wnd_rect.m_top = m_wnd_rect.m_bottom + 1; - m_list_wnd_rect.m_bottom = m_list_wnd_rect.m_top + m_item_total * ITEM_HEIGHT; - get_screen_rect(m_list_screen_rect); - m_list_screen_rect.m_top = m_list_screen_rect.m_bottom + 1; - m_list_screen_rect.m_bottom = m_list_screen_rect.m_top + m_item_total * ITEM_HEIGHT; - } - void show_list() - { - //draw all items - c_rect tmp_rect; - for (int i = 0; i < m_item_total; i++) - { - tmp_rect.m_left = m_list_screen_rect.m_left; - tmp_rect.m_right = m_list_screen_rect.m_right; - tmp_rect.m_top = m_list_screen_rect.m_top + i * ITEM_HEIGHT; - tmp_rect.m_bottom = tmp_rect.m_top + ITEM_HEIGHT; - if (m_selected_item == i) - { - m_surface->fill_rect(tmp_rect, c_theme::get_color(COLOR_WND_FOCUS), m_z_order); - c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[i], tmp_rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_FOCUS), ALIGN_HCENTER | ALIGN_VCENTER); - } - else - { - m_surface->fill_rect(tmp_rect, GL_RGB(17, 17, 17), m_z_order); - c_word::draw_string_in_rect(m_surface, m_z_order, m_item_array[i], tmp_rect, m_font, m_font_color, GL_RGB(17, 17, 17), ALIGN_HCENTER | ALIGN_VCENTER); - } - } - } - void on_touch_down(int x, int y) - { - if (m_wnd_rect.pt_in_rect(x, y)) - {//click base - if (STATUS_NORMAL == m_status) - { - m_parent->set_child_focus(this); - } - } - else if (m_list_wnd_rect.pt_in_rect(x, y)) - {//click extend list - c_wnd::on_touch(x, y, TOUCH_DOWN); - } - else - { - if (STATUS_PUSHED == m_status) - { - m_status = STATUS_FOCUSED; - on_paint(); - if(on_change) - { - (m_parent->*(on_change))(m_id, m_selected_item); - } - } - } - } - void on_touch_up(int x, int y) - { - if (STATUS_FOCUSED == m_status) - { - m_status = STATUS_PUSHED; - on_paint(); - } - else if (STATUS_PUSHED == m_status) - { - if (m_wnd_rect.pt_in_rect(x, y)) - {//click base - m_status = STATUS_FOCUSED; - on_paint(); - } - else if (m_list_wnd_rect.pt_in_rect(x, y)) - {//click extend list - m_status = STATUS_FOCUSED; - select_item((y - m_list_wnd_rect.m_top) / ITEM_HEIGHT); - on_paint(); - if(on_change) - { - (m_parent->*(on_change))(m_id, m_selected_item); - } - } - else - { - c_wnd::on_touch(x, y, TOUCH_UP); - } - } - } - short m_selected_item; - short m_item_total; - char* m_item_array[MAX_ITEM_NUM]; - c_rect m_list_wnd_rect; //rect relative to parent wnd. - c_rect m_list_screen_rect; //rect relative to physical screen(frame buffer) - WND_CALLBACK on_change; -}; -#include -#define MAX_PAGES 5 -class c_gesture; -class c_slide_group : public c_wnd { -public: - inline c_slide_group(); - int set_active_slide(int index, bool is_redraw = true) - { - if (index >= MAX_PAGES || index < 0) - { - return -1; - } - if (0 == m_slides[index]) - { - return -2; - } - m_active_slide_index = index; - for (int i = 0; i < MAX_PAGES; i++) - { - if (m_slides[i] == 0) - { - continue; - } - if (i == index) - { - m_slides[i]->get_surface()->set_active(true); - add_child_2_tail(m_slides[i]); - if (is_redraw) - { - c_rect rc; - get_screen_rect(rc); - m_slides[i]->get_surface()->flush_screen(rc.m_left, rc.m_top, rc.m_right, rc.m_bottom); - } - } - else - { - m_slides[i]->get_surface()->set_active(false); - } - } - return 0; - } - c_wnd* get_slide(int index){return m_slides[index];} - c_wnd* get_active_slide(){return m_slides[m_active_slide_index];} - int get_active_slide_index(){return m_active_slide_index;} - int add_slide(c_wnd* slide, unsigned short resource_id, short x, short y, short width, short height, WND_TREE* p_child_tree = 0, Z_ORDER_LEVEL max_zorder = Z_ORDER_LEVEL_0) - { - if (0 == slide) - { - return -1; - } - c_surface* old_surface = get_surface(); - c_surface* new_surface = old_surface->get_display()->alloc_surface(max_zorder); - new_surface->set_active(false); - set_surface(new_surface); - slide->connect(this, resource_id, 0, x, y, width, height, p_child_tree); - set_surface(old_surface); - int i = 0; - while (i < MAX_PAGES) - { - if (m_slides[i] == slide) - {//slide has lived - ASSERT(false); - return -2; - } - i++; - } - //new slide - i = 0; - while (i < MAX_PAGES) - { - if (m_slides[i] == 0) - { - m_slides[i] = slide; - slide->show_window(); - return 0; - } - i++; - } - //no more slide can be add - ASSERT(false); - return -3; - } - void disabel_all_slide() - { - for (int i = 0; i < MAX_PAGES; i++) - { - if (m_slides[i]) - { - m_slides[i]->get_surface()->set_active(false); - } - } - } - inline virtual void on_touch(int x, int y, TOUCH_ACTION action); - virtual void on_navigate(NAVIGATION_KEY key) - { - if (m_slides[m_active_slide_index]) - { - m_slides[m_active_slide_index]->on_navigate(key); - } - } -protected: - c_wnd* m_slides[MAX_PAGES]; - int m_active_slide_index; - c_gesture* m_gesture; -}; -//#define SWIPE_STEP 300//for arm -#define SWIPE_STEP 10//for PC & ANDROID -#define MOVE_THRESHOLD 10 -typedef enum { - TOUCH_MOVE, - TOUCH_IDLE -}TOUCH_STATE; -class c_slide_group; -class c_gesture { -public: - c_gesture(c_slide_group* group) - { - m_slide_group = group; - m_state = TOUCH_IDLE; - m_down_x = m_down_y = m_move_x = m_move_y = 0; - } - bool handle_swipe(int x, int y, TOUCH_ACTION action) - { - if (action == TOUCH_DOWN)//MOUSE_LBUTTONDOWN - { - if (m_state == TOUCH_IDLE) - { - m_state = TOUCH_MOVE; - m_move_x = m_down_x = x; - return true; - } - else//TOUCH_MOVE - { - return on_move(x); - } - } - else if (action == TOUCH_UP)//MOUSE_LBUTTONUP - { - if (m_state == TOUCH_MOVE) - { - m_state = TOUCH_IDLE; - return on_swipe(x); - } - else - { - return false; - //ASSERT(false); - } - } - return true; - } -private: - bool on_move(int x) - { - if (m_slide_group == 0) - { - return true; - } - if (abs(x - m_move_x) < MOVE_THRESHOLD) - { - return false; - } - m_slide_group->disabel_all_slide(); - m_move_x = x; - if ((m_move_x - m_down_x) > 0) - { - move_right(); - } - else - { - move_left(); - } - return false; - } - bool on_swipe(int x) - { - if (m_slide_group == 0) - { - return true; - } - if ((m_down_x == m_move_x) && (abs(x - m_down_x) < MOVE_THRESHOLD)) - { - return true; - } - m_slide_group->disabel_all_slide(); - int page = -1; - m_move_x = x; - if ((m_move_x - m_down_x) > 0) - { - page = swipe_right(); - } - else - { - page = swipe_left(); - } - if (page >= 0) - { - m_slide_group->set_active_slide(page); - } - else - { - m_slide_group->set_active_slide(m_slide_group->get_active_slide_index(), false); - } - return false; - } - int swipe_left() - { - if (m_slide_group == 0) - { - return -1; - } - int index = m_slide_group->get_active_slide_index(); - if ((index + 1) >= MAX_PAGES || - m_slide_group->get_slide(index + 1) == 0 || - m_slide_group->get_slide(index) == 0) - { - return -2; - } - c_surface* s1 = m_slide_group->get_slide(index + 1)->get_surface(); - c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); - if (s1->get_display() != s2->get_display()) - { - return -3; - } - int step = m_down_x - m_move_x; - c_rect rc; - m_slide_group->get_screen_rect(rc); - while (step < rc.width()) - { - s1->get_display()->swipe_surface(s2, s1, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, step); - step += SWIPE_STEP; - } - if (step != rc.width()) - { - s1->get_display()->swipe_surface(s2, s1, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, rc.width()); - } - return (index + 1); - } - int swipe_right() - { - if (m_slide_group == 0) - { - return -1; - } - int index = m_slide_group->get_active_slide_index(); - if (index <= 0 || - m_slide_group->get_slide(index - 1) == 0 || - m_slide_group->get_slide(index) == 0) - { - return -2; - } - c_surface* s1 = m_slide_group->get_slide(index - 1)->get_surface(); - c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); - if (s1->get_display() != s2->get_display()) - { - return -3; - } - c_rect rc; - m_slide_group->get_screen_rect(rc); - int step = rc.width() - (m_move_x - m_down_x); - while (step > 0) - { - s1->get_display()->swipe_surface(s1, s2, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, step); - step -= SWIPE_STEP; - } - if (step != 0) - { - s1->get_display()->swipe_surface(s1, s2, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, 0); - } - return (index - 1); - } - void move_left() - { - int index = m_slide_group->get_active_slide_index(); - if ((index + 1) >= MAX_PAGES || - m_slide_group->get_slide(index + 1) == 0 || - m_slide_group->get_slide(index) == 0) - { - return; - } - c_surface* s1 = m_slide_group->get_slide(index + 1)->get_surface(); - c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); - c_rect rc; - m_slide_group->get_screen_rect(rc); - if (s1->get_display() == s2->get_display()) - { - s1->get_display()->swipe_surface(s2, s1, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, (m_down_x - m_move_x)); - } - } - void move_right() - { - int index = m_slide_group->get_active_slide_index(); - if (index <= 0 || - m_slide_group->get_slide(index - 1) == 0 || - m_slide_group->get_slide(index) == 0) - { - return; - } - c_surface* s1 = m_slide_group->get_slide(index - 1)->get_surface(); - c_surface * s2 = m_slide_group->get_slide(index)->get_surface(); - c_rect rc; - m_slide_group->get_screen_rect(rc); - if (s1->get_display() == s2->get_display()) - { - s1->get_display()->swipe_surface(s1, s2, rc.m_left, rc.m_right, rc.m_top, rc.m_bottom, (rc.width() - (m_move_x - m_down_x))); - } - } - int m_down_x; - int m_down_y; - int m_move_x; - int m_move_y; - TOUCH_STATE m_state; - c_slide_group* m_slide_group; -}; -inline c_slide_group::c_slide_group() -{ - m_gesture = new c_gesture(this); - for (int i = 0; i < MAX_PAGES; i++) - { - m_slides[i] = 0; - } - m_active_slide_index = 0; -} -inline void c_slide_group::on_touch(int x, int y, TOUCH_ACTION action) -{ - x -= m_wnd_rect.m_left; - y -= m_wnd_rect.m_top; - if (m_gesture->handle_swipe(x, y, action)) - { - if (m_slides[m_active_slide_index]) - { - m_slides[m_active_slide_index]->on_touch(x, y, action); - } - } -} -#define ID_BT_ARROW_UP 0x1111 -#define ID_BT_ARROW_DOWN 0x2222 -class c_spin_box; -class c_spin_button : public c_button -{ - friend class c_spin_box; - inline virtual void on_touch(int x, int y, TOUCH_ACTION action); - c_spin_box* m_spin_box; -}; -class c_spin_box : public c_wnd -{ - friend class c_spin_button; -public: - short get_value() { return m_value; } - void set_value(unsigned short value) { m_value = m_cur_value = value; } - void set_max_min(short max, short min) { m_max = max; m_min = min; } - void set_step(short step) { m_step = step; } - short get_min() { return m_min; } - short get_max() { return m_max; } - short get_step() { return m_step; } - void set_value_digit(short digit) { m_digit = digit; } - short get_value_digit() { return m_digit; } - void set_on_change(WND_CALLBACK on_change) { this->on_change = on_change; } -protected: - virtual void on_paint() - { - c_rect rect; - get_screen_rect(rect); - rect.m_right = rect.m_left + (rect.width() * 2 / 3); - m_surface->fill_rect(rect, c_theme::get_color(COLOR_WND_NORMAL), m_z_order); - c_word::draw_value_in_rect(m_surface, m_parent->get_z_order(), m_cur_value, m_digit, rect, m_font, m_font_color, c_theme::get_color(COLOR_WND_NORMAL), ALIGN_HCENTER | ALIGN_VCENTER); - } - virtual void pre_create_wnd() - { - m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE); - m_font = c_theme::get_font(FONT_DEFAULT); - m_font_color = c_theme::get_color(COLOR_WND_FONT); - m_max = 6; - m_min = 1; - m_digit = 0; - m_step = 1; - //link arrow button position. - c_rect rect; - get_wnd_rect(rect); - m_bt_down.m_spin_box = m_bt_up.m_spin_box = this; - m_bt_up.connect(m_parent, ID_BT_ARROW_UP, "+", (rect.m_left + rect.width() * 2 / 3), rect.m_top, (rect.width() / 3), (rect.height() / 2)); - m_bt_down.connect(m_parent, ID_BT_ARROW_DOWN, "-", (rect.m_left + rect.width() * 2 / 3), (rect.m_top + rect.height() / 2), (rect.width() / 3), (rect.height() / 2)); - } - void on_arrow_up_bt_click() - { - if (m_cur_value + m_step > m_max) - { - return; - } - m_cur_value += m_step; - if(on_change) - { - (m_parent->*(on_change))(m_id, m_cur_value); - } - on_paint(); - } - void on_arrow_down_bt_click() - { - if (m_cur_value - m_step < m_min) - { - return; - } - m_cur_value -= m_step; - if(on_change) - { - (m_parent->*(on_change))(m_id, m_cur_value); - } - on_paint(); - } - short m_cur_value; - short m_value; - short m_step; - short m_max; - short m_min; - short m_digit; - c_spin_button m_bt_up; - c_spin_button m_bt_down; - WND_CALLBACK on_change; -}; -inline void c_spin_button::on_touch(int x, int y, TOUCH_ACTION action) -{ - if (action == TOUCH_UP) - { - (m_id == ID_BT_ARROW_UP) ? m_spin_box->on_arrow_up_bt_click() : m_spin_box->on_arrow_down_bt_click(); - } - c_button::on_touch(x, y, action); -} -#define MAX_COL_NUM 30 -#define MAX_ROW_NUM 30 -class c_table: public c_wnd -{ -public: - void set_sheet_align(unsigned int align_type){ m_align_type = align_type;} - void set_row_num(unsigned int row_num){ m_row_num = row_num;} - void set_col_num(unsigned int col_num){ m_col_num = col_num;} - void set_row_height(unsigned int height) - { - for (unsigned int i = 0; i < m_row_num; i++) - { - m_row_height[i] = height; - } - } - void set_col_width(unsigned int width) - { - for (unsigned int i = 0; i < m_col_num; i++) - { - m_col_width[i] = width; - } - } - int set_row_height(unsigned int index, unsigned int height) - { - if (m_row_num > index) - { - m_row_height[index] = height; - return index; - } - return -1; - } - int set_col_width(unsigned int index, unsigned int width) - { - if (m_col_num > index) - { - m_col_width[index] = width; - return index; - } - return -1; - } - void set_item(int row, int col, char* str, unsigned int color) - { - draw_item(row, col, str, color); - } - unsigned int get_row_num(){ return m_row_num;} - unsigned int get_col_num(){ return m_col_num;} - c_rect get_item_rect(int row, int col) - { - static c_rect rect; - if (row >= MAX_ROW_NUM || col >= MAX_COL_NUM) - { - return rect; - } - unsigned int width = 0; - unsigned int height = 0; - for (int i = 0; i < col; i++) - { - width += m_col_width[i]; - } - for (int j = 0; j < row; j++) - { - height += m_row_height[j]; - } - c_rect wRect; - get_screen_rect(wRect); - rect.m_left = wRect.m_left + width; - rect.m_right = rect.m_left + m_col_width[col]; - if (rect.m_right > wRect.m_right) - { - rect.m_right = wRect.m_right; - } - rect.m_top = wRect.m_top + height; - rect.m_bottom = rect.m_top + m_row_height[row]; - if (rect.m_bottom > wRect.m_bottom) - { - rect.m_bottom = wRect.m_bottom; - } - return rect; - } -protected: - virtual void pre_create_wnd() - { - m_attr = (WND_ATTRIBUTION)(ATTR_VISIBLE); - m_font = c_theme::get_font(FONT_DEFAULT); - m_font_color = c_theme::get_color(COLOR_WND_FONT); - } - void draw_item(int row, int col, const char* str, unsigned int color) - { - c_rect rect = get_item_rect(row, col); - m_surface->fill_rect(rect.m_left + 1, rect.m_top + 1, rect.m_right - 1, rect.m_bottom - 1, color, m_z_order); - c_word::draw_string_in_rect(m_surface, m_z_order, str, rect, m_font, m_font_color, GL_ARGB(0, 0, 0, 0), m_align_type); - } - unsigned int m_align_type; - unsigned int m_row_num; - unsigned int m_col_num; - unsigned int m_row_height[MAX_ROW_NUM]; - unsigned int m_col_width[MAX_COL_NUM]; -}; -#include -#include -#define WAVE_BUFFER_LEN 1024 -#define WAVE_READ_CACHE_LEN 8 -#define BUFFER_EMPTY -1111 -#define BUFFER_FULL -2222; -class c_wave_buffer -{ -public: - c_wave_buffer() - { - m_head = m_tail = m_min_old = m_max_old = - m_min_older = m_max_older = m_last_data = m_read_cache_sum = m_refresh_sequence = 0; - memset(m_wave_buf, 0, sizeof(m_wave_buf)); - memset(m_read_cache_min, 0, sizeof(m_read_cache_min)); - memset(m_read_cache_mid, 0, sizeof(m_read_cache_mid)); - memset(m_read_cache_max, 0, sizeof(m_read_cache_max)); - } - int write_wave_data(short data) - { - if ((m_tail + 1) % WAVE_BUFFER_LEN == m_head) - {//full - //log_out("wave buf full\n"); - return BUFFER_FULL; - } - m_wave_buf[m_tail] = data; - m_tail = (m_tail + 1) % WAVE_BUFFER_LEN; - return 1; - } - int read_wave_data_by_frame(short &max, short &min, short frame_len, unsigned int sequence, short offset) - { - if (m_refresh_sequence != sequence) - { - m_refresh_sequence = sequence; - m_read_cache_sum = 0; - } - else if (offset < m_read_cache_sum)//(m_refresh_sequence == sequence && offset < m_fb_sum) - { - max = m_read_cache_max[offset]; - min = m_read_cache_min[offset]; - return m_read_cache_mid[offset]; - } - m_read_cache_sum++; - ASSERT(m_read_cache_sum <= WAVE_READ_CACHE_LEN); - int i, data; - int tmp_min = m_last_data; - int tmp_max = m_last_data; - int mid = (m_min_old + m_max_old) >> 1; - i = 0; - while (i++ < frame_len) - { - data = read_data(); - if (BUFFER_EMPTY == data) - { - break; - } - m_last_data = data; - if (data < tmp_min) { tmp_min = data; } - if (data > tmp_max) { tmp_max = data; } - } - min = m_read_cache_min[offset] = MIN(m_min_old, MIN(tmp_min, m_min_older)); - max = m_read_cache_max[offset] = MAX(m_max_old, MAX(tmp_max, m_max_older)); - m_min_older = m_min_old; - m_max_older = m_max_old; - m_min_old = tmp_min; - m_max_old = tmp_max; - return (m_read_cache_mid[offset] = mid); - } - void reset() - { - m_head = m_tail; - } - void clear_data() - { - m_head = m_tail = 0; - memset(m_wave_buf, 0, sizeof(m_wave_buf)); - } - short get_cnt() - { - return (m_tail >= m_head) ? (m_tail - m_head) : (m_tail - m_head + WAVE_BUFFER_LEN); - } -private: - int read_data() - { - if (m_head == m_tail) - {//empty - //log_out("wave buf empty\n"); - return BUFFER_EMPTY; - } - int ret = m_wave_buf[m_head]; - m_head = (m_head + 1) % WAVE_BUFFER_LEN; - return ret; - } - short m_wave_buf[WAVE_BUFFER_LEN]; - short m_head; - short m_tail; - int m_min_old; - int m_max_old; - int m_min_older; - int m_max_older; - int m_last_data; - short m_read_cache_min[WAVE_READ_CACHE_LEN]; - short m_read_cache_mid[WAVE_READ_CACHE_LEN]; - short m_read_cache_max[WAVE_READ_CACHE_LEN]; - short m_read_cache_sum; - unsigned int m_refresh_sequence; -}; -#include -#include -#define CORRECT(x, high_limit, low_limit) {\ - x = (x > high_limit) ? high_limit : x;\ - x = (x < low_limit) ? low_limit : x;\ -}while(0) -#define WAVE_CURSOR_WIDTH 8 -#define WAVE_LINE_WIDTH 1 -#define WAVE_MARGIN 5 -typedef enum -{ - FILL_MODE, - SCAN_MODE -}E_WAVE_DRAW_MODE; -class c_wave_buffer; -class c_wave_ctrl : public c_wnd -{ -public: - c_wave_ctrl() - { - m_wave = 0; - m_bg_fb = 0; - m_wave_name_font = m_wave_unit_font = 0; - m_wave_name = m_wave_unit = 0; - m_max_data = 500; - m_min_data = 0; - m_wave_speed = 1; - m_wave_data_rate = 0; - m_wave_refresh_rate = 1000; - m_frame_len_map_index = 0; - m_wave_name_color = m_wave_unit_color = m_wave_color = GL_RGB(255, 0, 0); - m_back_color = GL_RGB(0, 0, 0); - } - virtual void on_init_children()//should be pre_create - { - c_rect rect; - get_screen_rect(rect); - m_wave_left = rect.m_left + WAVE_MARGIN; - m_wave_right = rect.m_right - WAVE_MARGIN; - m_wave_top = rect.m_top + WAVE_MARGIN; - m_wave_bottom = rect.m_bottom - WAVE_MARGIN; - m_wave_cursor = m_wave_left; - m_bg_fb = (unsigned int*)calloc(rect.width() * rect.height(), 4); - } - virtual void on_paint() - { - c_rect rect; - get_screen_rect(rect); - m_surface->fill_rect(rect, m_back_color, m_z_order); - //show name - c_word::draw_string(m_surface, m_z_order, m_wave_name, m_wave_left + 10, rect.m_top, m_wave_name_font, m_wave_name_color, GL_ARGB(0, 0, 0, 0)); - //show unit - c_word::draw_string(m_surface, m_z_order, m_wave_unit, m_wave_left + 60, rect.m_top, m_wave_unit_font, m_wave_unit_color, GL_ARGB(0, 0, 0, 0)); - save_background(); - } - void set_wave_name(char* wave_name){ m_wave_name = wave_name;} - void set_wave_unit(char* wave_unit){ m_wave_unit = wave_unit;} - void set_wave_name_font(const LATTICE_FONT_INFO* wave_name_font_type){ m_wave_name_font = wave_name_font_type;} - void set_wave_unit_font(const LATTICE_FONT_INFO* wave_unit_font_type){ m_wave_unit_font = wave_unit_font_type;} - void set_wave_name_color(unsigned int wave_name_color){ m_wave_name_color = wave_name_color;} - void set_wave_unit_color(unsigned int wave_unit_color){ m_wave_unit_color = wave_unit_color;} - void set_wave_color(unsigned int color){ m_wave_color = color;} - void set_wave_in_out_rate(unsigned int data_rate, unsigned int refresh_rate) - { - m_wave_data_rate = data_rate; - m_wave_refresh_rate = refresh_rate; - int read_times_per_second = m_wave_speed * 1000 / m_wave_refresh_rate; - memset(m_frame_len_map, 0, sizeof(m_frame_len_map)); - for (unsigned int i = 1; i < sizeof(m_frame_len_map) + 1; i++) - { - m_frame_len_map[i - 1] = data_rate * i / read_times_per_second - data_rate * (i - 1) / read_times_per_second; - } - m_frame_len_map_index = 0; - } - void set_wave_speed(unsigned int speed) - { - m_wave_speed = speed; - set_wave_in_out_rate(m_wave_data_rate, m_wave_refresh_rate); - } - void set_max_min(short max_data, short min_data) - { - m_max_data = max_data; - m_min_data = min_data; - } - void set_wave(c_wave_buffer* wave){m_wave = wave;} - c_wave_buffer* get_wave(){return m_wave;} - void clear_data() - { - if (m_wave == 0) - { - ASSERT(false); - return; - } - m_wave->clear_data(); - } - bool is_data_enough() - { - if (m_wave == 0) - { - ASSERT(false); - return false; - } - return (m_wave->get_cnt() - m_frame_len_map[m_frame_len_map_index] * m_wave_speed); - } - void refresh_wave(unsigned char frame) - { - if (m_wave == 0) - { - ASSERT(false); - return; - } - short max, min, mid; - for (short offset = 0; offset < m_wave_speed; offset++) - { - //get wave value - mid = m_wave->read_wave_data_by_frame(max, min, - m_frame_len_map[m_frame_len_map_index++], - frame, offset); - m_frame_len_map_index %= sizeof(m_frame_len_map); - //map to wave ctrl - int y_min, y_max; - if (m_max_data == m_min_data) - { - ASSERT(false); - } - y_max = m_wave_bottom + WAVE_LINE_WIDTH - (m_wave_bottom - m_wave_top) * (min - m_min_data) / (m_max_data - m_min_data); - y_min = m_wave_bottom - WAVE_LINE_WIDTH - (m_wave_bottom - m_wave_top) * (max - m_min_data) / (m_max_data - m_min_data); - mid = m_wave_bottom - (m_wave_bottom - m_wave_top) * (mid - m_min_data) / (m_max_data - m_min_data); - CORRECT(y_min, m_wave_bottom, m_wave_top); - CORRECT(y_max, m_wave_bottom, m_wave_top); - CORRECT(mid, m_wave_bottom, m_wave_top); - if (m_wave_cursor > m_wave_right) - { - m_wave_cursor = m_wave_left; - } - draw_smooth_vline(y_min, y_max, mid, m_wave_color); - restore_background(); - m_wave_cursor++; - } - } - void clear_wave() - { - m_surface->fill_rect(m_wave_left, m_wave_top, m_wave_right, m_wave_bottom, m_back_color, m_z_order); - m_wave_cursor = m_wave_left; - } -protected: - void draw_smooth_vline(int y_min, int y_max, int mid, unsigned int rgb) - { - int dy = y_max - y_min; - short r = GL_RGB_R(rgb); - short g = GL_RGB_G(rgb); - short b = GL_RGB_B(rgb); - int index = (dy >> 1) + 2; - int y; - m_surface->draw_pixel(m_wave_cursor, mid, rgb, m_z_order); - if (dy < 1) - { - return; - } - unsigned char cur_r, cur_g, cur_b; - unsigned int cur_rgb; - for (int i = 1; i <= (dy >> 1) + 1; ++i) - { - if ((mid + i) <= y_max) - { - y = mid + i; - cur_r = r * (index - i) / index; - cur_g = g * (index - i) / index; - cur_b = b * (index - i) / index; - cur_rgb = GL_RGB(cur_r, cur_g, cur_b); - m_surface->draw_pixel(m_wave_cursor, y, cur_rgb, m_z_order); - } - if ((mid - i) >= y_min) - { - y = mid - i; - cur_r = r * (index - i) / index; - cur_g = g * (index - i) / index; - cur_b = b * (index - i) / index; - cur_rgb = GL_RGB(cur_r, cur_g, cur_b); - m_surface->draw_pixel(m_wave_cursor, y, cur_rgb, m_z_order); - } - } - } - void restore_background() - { - int x = m_wave_cursor + WAVE_CURSOR_WIDTH; - if (x > m_wave_right) - { - x -= (m_wave_right - m_wave_left + 1); - } - c_rect rect; - get_screen_rect(rect); - register int width = rect.width(); - register int top = rect.m_top; - register int left = rect.m_left; - for (int y_pos = (m_wave_top - 1); y_pos <= (m_wave_bottom + 1); y_pos++) - { - (m_bg_fb) ? m_surface->draw_pixel(x, y_pos, m_bg_fb[(y_pos - top) * width + (x - left)], m_z_order) : m_surface->draw_pixel(x, y_pos, 0, m_z_order); - } - } - void save_background() - { - if (!m_bg_fb) - { - return; - } - c_rect rect; - get_screen_rect(rect); - register unsigned int* p_des = m_bg_fb; - for (int y = rect.m_top; y <= rect.m_bottom; y++) - { - for (int x = rect.m_left; x <= rect.m_right; x++) - { - *p_des++ = m_surface->get_pixel(x, y, m_z_order); - } - } - } - char* m_wave_name; - char* m_wave_unit; - const LATTICE_FONT_INFO* m_wave_name_font; - const LATTICE_FONT_INFO* m_wave_unit_font; - unsigned int m_wave_name_color; - unsigned int m_wave_unit_color; - unsigned int m_wave_color; - unsigned int m_back_color; - int m_wave_left; - int m_wave_right; - int m_wave_top; - int m_wave_bottom; - short m_max_data; - short m_min_data; - -private: - c_wave_buffer* m_wave; - unsigned int* m_bg_fb; //background frame buffer, could be used to draw scale line. - int m_wave_cursor; - int m_wave_speed; //pixels per refresh - unsigned int m_wave_data_rate; //data sample rate - unsigned int m_wave_refresh_rate;//refresh cycle in millisecond - unsigned char m_frame_len_map[64]; - unsigned char m_frame_len_map_index; -}; -#ifdef GUILITE_ON -c_bitmap_operator the_bitmap_op = c_bitmap_operator(); -c_image_operator* c_image::image_operator = &the_bitmap_op; -#endif - -#ifdef GUILITE_ON - -const void* c_theme::s_font_map[FONT_MAX]; -const void* c_theme::s_image_map[IMAGE_MAX]; -unsigned int c_theme::s_color_map[COLOR_MAX]; - -#endif - -#ifdef GUILITE_ON - -c_lattice_font_op the_lattice_font_op = c_lattice_font_op(); -c_font_operator* c_word::fontOperator = &the_lattice_font_op; - -#endif -#ifdef GUILITE_ON -#if (defined __linux__) || (defined __APPLE__) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define MAX_TIMER_CNT 10 -#define TIMER_UNIT 50//ms -static void(*do_assert)(const char* file, int line); -static void(*do_log_out)(const char* log); -void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)) -{ - do_assert = my_assert; - do_log_out = my_log_out; -} -void _assert(const char* file, int line) -{ - if(do_assert) - { - do_assert(file, line); - } - else - { - printf("assert@ file:%s, line:%d, error no: %d\n", file, line, errno); - } -} -void log_out(const char* log) -{ - if (do_log_out) - { - do_log_out(log); - } - else - { - printf("%s", log); - fflush(stdout); - } -} -typedef struct _timer_manage -{ - struct _timer_info - { - int state; /* on or off */ - int interval; - int elapse; /* 0~interval */ - void (* timer_proc) (void* param); - void* param; - }timer_info[MAX_TIMER_CNT]; - void (* old_sigfunc)(int); - void (* new_sigfunc)(int); -}_timer_manage_t; -static struct _timer_manage timer_manage; -static void* timer_routine(void*) -{ - int i; - while(true) - { - for(i = 0; i < MAX_TIMER_CNT; i++) - { - if(timer_manage.timer_info[i].state == 0) - { - continue; - } - timer_manage.timer_info[i].elapse++; - if(timer_manage.timer_info[i].elapse == timer_manage.timer_info[i].interval) - { - timer_manage.timer_info[i].elapse = 0; - timer_manage.timer_info[i].timer_proc(timer_manage.timer_info[i].param); - } - } - usleep(1000 * TIMER_UNIT); - } - return NULL; -} -static int init_mul_timer() -{ - static bool s_is_init = false; - if(s_is_init == true) - { - return 0; - } - memset(&timer_manage, 0, sizeof(struct _timer_manage)); - pthread_t pid; - pthread_create(&pid, NULL, timer_routine, NULL); - s_is_init = true; - return 1; -} -static int set_a_timer(int interval, void (* timer_proc)(void* param), void* param) -{ - init_mul_timer(); - int i; - if(timer_proc == NULL || interval <= 0) - { - return (-1); - } - for(i = 0; i < MAX_TIMER_CNT; i++) - { - if(timer_manage.timer_info[i].state == 1) - { - continue; - } - memset(&timer_manage.timer_info[i], 0, sizeof(timer_manage.timer_info[i])); - timer_manage.timer_info[i].timer_proc = timer_proc; - timer_manage.timer_info[i].param = param; - timer_manage.timer_info[i].interval = interval; - timer_manage.timer_info[i].elapse = 0; - timer_manage.timer_info[i].state = 1; - break; - } - if(i >= MAX_TIMER_CNT) - { - ASSERT(false); - return (-1); - } - return (i); -} -typedef void (*EXPIRE_ROUTINE)(void* arg); -EXPIRE_ROUTINE s_expire_function; -static c_fifo s_real_timer_fifo; -static void* real_timer_routine(void*) -{ - char dummy; - while(1) - { - if(s_real_timer_fifo.read(&dummy, 1) > 0) - { - if(s_expire_function)s_expire_function(0); - } - else - { - ASSERT(false); - } - } - return 0; -} -static void expire_real_timer(int sigo) -{ - char dummy = 0x33; - if(s_real_timer_fifo.write(&dummy, 1) <= 0) - { - ASSERT(false); - } -} -void start_real_timer(void (*func)(void* arg)) -{ - if(NULL == func) - { - return; - } - s_expire_function = func; - signal(SIGALRM, expire_real_timer); - struct itimerval value, ovalue; - value.it_value.tv_sec = 0; - value.it_value.tv_usec = REAL_TIME_TASK_CYCLE_MS * 1000; - value.it_interval.tv_sec = 0; - value.it_interval.tv_usec = REAL_TIME_TASK_CYCLE_MS * 1000; - setitimer(ITIMER_REAL, &value, &ovalue); - static pthread_t s_pid; - if(s_pid == 0) - { - pthread_create(&s_pid, NULL, real_timer_routine, NULL); - } -} -unsigned int get_cur_thread_id() -{ - return (unsigned long)pthread_self(); -} -void register_timer(int milli_second,void func(void* param), void* param) -{ - set_a_timer(milli_second/TIMER_UNIT,func, param); -} -long get_time_in_second() -{ - return time(NULL); /* + 8*60*60*/ -} -T_TIME get_time() -{ - T_TIME ret = {0}; - struct tm *fmt; - time_t timer; - timer = get_time_in_second(); - fmt = localtime(&timer); - ret.year = fmt->tm_year + 1900; - ret.month = fmt->tm_mon + 1; - ret.day = fmt->tm_mday; - ret.hour = fmt->tm_hour; - ret.minute = fmt->tm_min; - ret.second = fmt->tm_sec; - return ret; -} -T_TIME second_to_day(long second) -{ - T_TIME ret = {0}; - struct tm *fmt; - fmt = localtime(&second); - ret.year = fmt->tm_year + 1900; - ret.month = fmt->tm_mon + 1; - ret.day = fmt->tm_mday; - ret.hour = fmt->tm_hour; - ret.minute = fmt->tm_min; - ret.second = fmt->tm_sec; - return ret; -} -void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg) -{ - pthread_create((pthread_t*)thread_id, (pthread_attr_t const*)attr, start_routine, arg); -} -void thread_sleep(unsigned int milli_seconds) -{ - usleep(milli_seconds * 1000); -} -typedef struct { - unsigned short bfType; - unsigned int bfSize; - unsigned short bfReserved1; - unsigned short bfReserved2; - unsigned int bfOffBits; -}__attribute__((packed))FileHead; -typedef struct{ - unsigned int biSize; - int biWidth; - int biHeight; - unsigned short biPlanes; - unsigned short biBitCount; - unsigned int biCompress; - unsigned int biSizeImage; - int biXPelsPerMeter; - int biYPelsPerMeter; - unsigned int biClrUsed; - unsigned int biClrImportant; - unsigned int biRedMask; - unsigned int biGreenMask; - unsigned int biBlueMask; -}__attribute__((packed))Infohead; -int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data) -{ - FileHead bmp_head; - Infohead bmp_info; - int size = width * height * 2; - //initialize bmp head. - bmp_head.bfType = 0x4d42; - bmp_head.bfSize = size + sizeof(FileHead) + sizeof(Infohead); - bmp_head.bfReserved1 = bmp_head.bfReserved2 = 0; - bmp_head.bfOffBits = bmp_head.bfSize - size; - //initialize bmp info. - bmp_info.biSize = 40; - bmp_info.biWidth = width; - bmp_info.biHeight = height; - bmp_info.biPlanes = 1; - bmp_info.biBitCount = 16; - bmp_info.biCompress = 3; - bmp_info.biSizeImage = size; - bmp_info.biXPelsPerMeter = 0; - bmp_info.biYPelsPerMeter = 0; - bmp_info.biClrUsed = 0; - bmp_info.biClrImportant = 0; - //RGB565 - bmp_info.biRedMask = 0xF800; - bmp_info.biGreenMask = 0x07E0; - bmp_info.biBlueMask = 0x001F; - //copy the data - FILE *fp; - if(!(fp=fopen(filename,"wb"))) - { - return -1; - } - fwrite(&bmp_head, 1, sizeof(FileHead),fp); - fwrite(&bmp_info, 1, sizeof(Infohead),fp); - //fwrite(data, 1, size, fp);//top <-> bottom - for (int i = (height - 1); i >= 0; --i) - { - fwrite(&data[i * width * 2], 1, width * 2, fp); - } - - fclose(fp); - return 0; -} -c_fifo::c_fifo() -{ - m_head = m_tail = 0; - m_read_sem = malloc(sizeof(sem_t)); - m_write_mutex = malloc(sizeof(pthread_mutex_t)); - - sem_init((sem_t*)m_read_sem, 0, 0); - pthread_mutex_init((pthread_mutex_t*)m_write_mutex, 0); -} -int c_fifo::read(void* buf, int len) -{ - unsigned char* pbuf = (unsigned char*)buf; - int i = 0; - while(i < len) - { - if (m_tail == m_head) - {//empty - sem_wait((sem_t*)m_read_sem); - continue; - } - *pbuf++ = m_buf[m_head]; - m_head = (m_head + 1) % FIFO_BUFFER_LEN; - i++; - } - if(i != len) - { - ASSERT(false); - } - return i; -} -int c_fifo::write(void* buf, int len) -{ - unsigned char* pbuf = (unsigned char*)buf; - int i = 0; - int tail = m_tail; - pthread_mutex_lock((pthread_mutex_t*)m_write_mutex); - while(i < len) - { - if ((m_tail + 1) % FIFO_BUFFER_LEN == m_head) - {//full, clear data has been written; - m_tail = tail; - log_out("Warning: fifo full\n"); - pthread_mutex_unlock((pthread_mutex_t*)m_write_mutex); - return 0; - } - m_buf[m_tail] = *pbuf++; - m_tail = (m_tail + 1) % FIFO_BUFFER_LEN; - i++; - } - pthread_mutex_unlock((pthread_mutex_t*)m_write_mutex); - if(i != len) - { - ASSERT(false); - } - else - { - sem_post((sem_t*)m_read_sem); - } - return i; -} -#endif -#endif -#ifdef GUILITE_ON -#if (!defined _WIN32) && (!defined WIN32) && (!defined _WIN64) && (!defined WIN64) && (!defined __linux__) && (!defined __APPLE__) - -#include - -static void(*do_assert)(const char* file, int line); -static void(*do_log_out)(const char* log); -void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)) -{ - do_assert = my_assert; - do_log_out = my_log_out; -} - -void _assert(const char* file, int line) -{ - if(do_assert) - { - do_assert(file, line); - } - while(1); -} - -void log_out(const char* log) -{ - if (do_log_out) - { - do_log_out(log); - } -} - -long get_time_in_second() -{ - return 0; -} - -T_TIME second_to_day(long second) -{ - T_TIME ret = {0}; - return ret; -} - -T_TIME get_time() -{ - T_TIME ret = {0}; - return ret; -} - -void start_real_timer(void (*func)(void* arg)) -{ - log_out("Not support now"); -} - -void register_timer(int milli_second, void func(void* ptmr, void* parg)) -{ - log_out("Not support now"); -} - -unsigned int get_cur_thread_id() -{ - log_out("Not support now"); - return 0; -} - -void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg) -{ - log_out("Not support now"); -} - -extern "C" void delay_ms(unsigned short nms); -void thread_sleep(unsigned int milli_seconds) -{//MCU alway implemnet driver code in APP. - delay_ms(milli_seconds); -} - -int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data) -{ - log_out("Not support now"); - return 0; -} - -c_fifo::c_fifo() -{ - m_head = m_tail = 0; - m_read_sem = m_write_mutex = 0; -} - -int c_fifo::read(void* buf, int len) -{ - unsigned char* pbuf = (unsigned char*)buf; - int i = 0; - while(i < len) - { - if (m_tail == m_head) - {//empty - continue; - } - *pbuf++ = m_buf[m_head]; - m_head = (m_head + 1) % FIFO_BUFFER_LEN; - i++; - } - if(i != len) - { - ASSERT(false); - } - return i; -} - -int c_fifo::write(void* buf, int len) -{ - unsigned char* pbuf = (unsigned char*)buf; - int i = 0; - int tail = m_tail; - - while(i < len) - { - if ((m_tail + 1) % FIFO_BUFFER_LEN == m_head) - {//full, clear data has been written; - m_tail = tail; - log_out("Warning: fifo full\n"); - return 0; - } - m_buf[m_tail] = *pbuf++; - m_tail = (m_tail + 1) % FIFO_BUFFER_LEN; - i++; - } - - if(i != len) - { - ASSERT(false); - } - return i; -} - -#endif -#endif -#ifdef GUILITE_ON -#if (defined _WIN32) || (defined WIN32) || (defined _WIN64) || (defined WIN64) -#include -#include -#include -#include -#include -#include -#define MAX_TIMER_CNT 10 -#define TIMER_UNIT 50//ms -static void(*do_assert)(const char* file, int line); -static void(*do_log_out)(const char* log); -void register_debug_function(void(*my_assert)(const char* file, int line), void(*my_log_out)(const char* log)) -{ - do_assert = my_assert; - do_log_out = my_log_out; -} -void _assert(const char* file, int line) -{ - static char s_buf[192]; - if (do_assert) - { - do_assert(file, line); - } - else - { - memset(s_buf, 0, sizeof(s_buf)); - sprintf_s(s_buf, sizeof(s_buf), "vvvvvvvvvvvvvvvvvvvvvvvvvvvv\n\nAssert@ file = %s, line = %d\n\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", file, line); - OutputDebugStringA(s_buf); - printf("%s", s_buf); - fflush(stdout); - assert(false); - } -} -void log_out(const char* log) -{ - if (do_log_out) - { - do_log_out(log); - } - else - { - printf("%s", log); - fflush(stdout); - OutputDebugStringA(log); - } -} -typedef struct _timer_manage -{ - struct _timer_info - { - int state; /* on or off */ - int interval; - int elapse; /* 0~interval */ - void (* timer_proc) (void* param); - void* param; - }timer_info[MAX_TIMER_CNT]; - void (* old_sigfunc)(int); - void (* new_sigfunc)(int); -}_timer_manage_t; -static struct _timer_manage timer_manage; -DWORD WINAPI timer_routine(LPVOID lpParam) -{ - int i; - while(true) - { - for(i = 0; i < MAX_TIMER_CNT; i++) - { - if(timer_manage.timer_info[i].state == 0) - { - continue; - } - timer_manage.timer_info[i].elapse++; - if(timer_manage.timer_info[i].elapse == timer_manage.timer_info[i].interval) - { - timer_manage.timer_info[i].elapse = 0; - timer_manage.timer_info[i].timer_proc(timer_manage.timer_info[i].param); - } - } - Sleep(TIMER_UNIT); - } - return 0; -} -static int init_mul_timer() -{ - static bool s_is_init = false; - if(s_is_init == true) - { - return 0; - } - memset(&timer_manage, 0, sizeof(struct _timer_manage)); - DWORD pid; - CreateThread(0, 0, timer_routine, 0, 0, &pid); - s_is_init = true; - return 1; -} -static int set_a_timer(int interval, void (* timer_proc) (void* param), void* param) -{ - init_mul_timer(); - int i; - if(timer_proc == 0 || interval <= 0) - { - return (-1); - } - for(i = 0; i < MAX_TIMER_CNT; i++) - { - if(timer_manage.timer_info[i].state == 1) - { - continue; - } - memset(&timer_manage.timer_info[i], 0, sizeof(timer_manage.timer_info[i])); - timer_manage.timer_info[i].timer_proc = timer_proc; - timer_manage.timer_info[i].param = param; - timer_manage.timer_info[i].interval = interval; - timer_manage.timer_info[i].elapse = 0; - timer_manage.timer_info[i].state = 1; - break; - } - if(i >= MAX_TIMER_CNT) - { - ASSERT(false); - return (-1); - } - return (i); -} -typedef void (*EXPIRE_ROUTINE)(void* arg); -EXPIRE_ROUTINE s_expire_function; -static c_fifo s_real_timer_fifo; -static DWORD WINAPI fire_real_timer(LPVOID lpParam) -{ - char dummy; - while(1) - { - if(s_real_timer_fifo.read(&dummy, 1) > 0) - { - if(s_expire_function)s_expire_function(0); - } - else - { - ASSERT(false); - } - } - return 0; -} -/*Win32 desktop only -static void CALLBACK trigger_real_timer(UINT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR) -{ - char dummy = 0x33; - s_real_timer_fifo.write(&dummy, 1); -} -*/ -static DWORD WINAPI trigger_real_timer(LPVOID lpParam) -{ - char dummy = 0x33; - while (1) - { - s_real_timer_fifo.write(&dummy, 1); - Sleep(REAL_TIME_TASK_CYCLE_MS); - } - return 0; -} -void start_real_timer(void (*func)(void* arg)) -{ - if(0 == func) - { - return; - } - s_expire_function = func; - //timeSetEvent(REAL_TIME_TASK_CYCLE_MS, 0, trigger_real_timer, 0, TIME_PERIODIC);//Win32 desktop only - static DWORD s_pid; - if(s_pid == 0) - { - CreateThread(0, 0, trigger_real_timer, 0, 0, &s_pid); - CreateThread(0, 0, fire_real_timer, 0, 0, &s_pid); - } -} -unsigned int get_cur_thread_id() -{ - return GetCurrentThreadId(); -} -void register_timer(int milli_second,void func(void* param), void* param) -{ - set_a_timer(milli_second/TIMER_UNIT,func, param); -} -long get_time_in_second() -{ - return (long)time(0); -} -T_TIME get_time() -{ - T_TIME ret = {0}; - - SYSTEMTIME time; - GetLocalTime(&time); - ret.year = time.wYear; - ret.month = time.wMonth; - ret.day = time.wDay; - ret.hour = time.wHour; - ret.minute = time.wMinute; - ret.second = time.wSecond; - return ret; -} -T_TIME second_to_day(long second) -{ - T_TIME ret; - ret.year = 1999; - ret.month = 10; - ret.date = 1; - ret.second = second % 60; - second /= 60; - ret.minute = second % 60; - second /= 60; - ret.hour = (second + 8) % 24;//China time zone. - return ret; -} -void create_thread(unsigned long* thread_id, void* attr, void *(*start_routine) (void *), void* arg) -{ - DWORD pid = 0; - CreateThread(0, 0, LPTHREAD_START_ROUTINE(start_routine), arg, 0, &pid); - *thread_id = pid; -} -void thread_sleep(unsigned int milli_seconds) -{ - Sleep(milli_seconds); -} -#pragma pack(push,1) -typedef struct { - unsigned short bfType; - unsigned int bfSize; - unsigned short bfReserved1; - unsigned short bfReserved2; - unsigned int bfOffBits; -}FileHead; -typedef struct { - unsigned int biSize; - int biWidth; - int biHeight; - unsigned short biPlanes; - unsigned short biBitCount; - unsigned int biCompress; - unsigned int biSizeImage; - int biXPelsPerMeter; - int biYPelsPerMeter; - unsigned int biClrUsed; - unsigned int biClrImportant; - unsigned int biRedMask; - unsigned int biGreenMask; - unsigned int biBlueMask; -}Infohead; -#pragma pack(pop) -int build_bmp(const char *filename, unsigned int width, unsigned int height, unsigned char *data) -{ - FileHead bmp_head; - Infohead bmp_info; - int size = width * height * 2; - //initialize bmp head. - bmp_head.bfType = 0x4d42; - bmp_head.bfSize = size + sizeof(FileHead) + sizeof(Infohead); - bmp_head.bfReserved1 = bmp_head.bfReserved2 = 0; - bmp_head.bfOffBits = bmp_head.bfSize - size; - //initialize bmp info. - bmp_info.biSize = 40; - bmp_info.biWidth = width; - bmp_info.biHeight = height; - bmp_info.biPlanes = 1; - bmp_info.biBitCount = 16; - bmp_info.biCompress = 3; - bmp_info.biSizeImage = size; - bmp_info.biXPelsPerMeter = 0; - bmp_info.biYPelsPerMeter = 0; - bmp_info.biClrUsed = 0; - bmp_info.biClrImportant = 0; - //RGB565 - bmp_info.biRedMask = 0xF800; - bmp_info.biGreenMask = 0x07E0; - bmp_info.biBlueMask = 0x001F; - //copy the data - FILE *fp; - if (!(fp = fopen(filename, "wb"))) - { - return -1; - } - fwrite(&bmp_head, 1, sizeof(FileHead), fp); - fwrite(&bmp_info, 1, sizeof(Infohead), fp); - //fwrite(data, 1, size, fp);//top <-> bottom - for (int i = (height - 1); i >= 0; --i) - { - fwrite(&data[i * width * 2], 1, width * 2, fp); - } - fclose(fp); - return 0; -} -c_fifo::c_fifo() -{ - m_head = m_tail = 0; - m_read_sem = CreateSemaphore(0, // default security attributes - 0, // initial count - 1, // maximum count - 0); // unnamed semaphore - m_write_mutex = CreateMutex(0, false, 0); -} -int c_fifo::read(void* buf, int len) -{ - unsigned char* pbuf = (unsigned char*)buf; - int i = 0; - while (i < len) - { - if (m_tail == m_head) - {//empty - WaitForSingleObject(m_read_sem, INFINITE); - continue; - } - *pbuf++ = m_buf[m_head]; - m_head = (m_head + 1) % FIFO_BUFFER_LEN; - i++; - } - if (i != len) - { - ASSERT(false); - } - return i; -} -int c_fifo::write(void* buf, int len) -{ - unsigned char* pbuf = (unsigned char*)buf; - int i = 0; - int tail = m_tail; - WaitForSingleObject(m_write_mutex, INFINITE); - while (i < len) - { - if ((m_tail + 1) % FIFO_BUFFER_LEN == m_head) - {//full, clear data has been written; - m_tail = tail; - log_out("Warning: fifo full\n"); - ReleaseMutex(m_write_mutex); - return 0; - } - m_buf[m_tail] = *pbuf++; - m_tail = (m_tail + 1) % FIFO_BUFFER_LEN; - i++; - } - ReleaseMutex(m_write_mutex); - if (i != len) - { - ASSERT(false); - } - else - { - ReleaseSemaphore(m_read_sem, 1, 0); - } - return i; -} -#endif -#endif -#ifdef GUILITE_ON -DIALOG_ARRAY c_dialog::ms_the_dialogs[SURFACE_CNT_MAX]; -#endif -#ifdef GUILITE_ON -c_keyboard c_edit::s_keyboard; -#endif -#ifdef GUILITE_ON -static c_keyboard_button s_key_0, s_key_1, s_key_2, s_key_3, s_key_4, s_key_5, s_key_6, s_key_7, s_key_8, s_key_9; -static c_keyboard_button s_key_A, s_key_B, s_key_C, s_key_D, s_key_E, s_key_F, s_key_G, s_key_H, s_key_I, s_key_J; -static c_keyboard_button s_key_K, s_key_L, s_key_M, s_key_N, s_key_O, s_key_P, s_key_Q, s_key_R, s_key_S, s_key_T; -static c_keyboard_button s_key_U, s_key_V, s_key_W, s_key_X, s_key_Y, s_key_Z; -static c_keyboard_button s_key_dot, s_key_caps, s_key_space, s_key_enter, s_key_del, s_key_esc, s_key_num_switch; -WND_TREE g_key_board_children[] = -{ - //Row 1 - {&s_key_Q, 'Q', 0, POS_X(0), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_W, 'W', 0, POS_X(1), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_E, 'E', 0, POS_X(2), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_R, 'R', 0, POS_X(3), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_T, 'T', 0, POS_X(4), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_Y, 'Y', 0, POS_X(5), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_U, 'U', 0, POS_X(6), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_I, 'I', 0, POS_X(7), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_O, 'O', 0, POS_X(8), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_P, 'P', 0, POS_X(9), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, - //Row 2 - {&s_key_A, 'A', 0, ((KEY_WIDTH / 2) + POS_X(0)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_S, 'S', 0, ((KEY_WIDTH / 2) + POS_X(1)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_D, 'D', 0, ((KEY_WIDTH / 2) + POS_X(2)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_F, 'F', 0, ((KEY_WIDTH / 2) + POS_X(3)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_G, 'G', 0, ((KEY_WIDTH / 2) + POS_X(4)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_H, 'H', 0, ((KEY_WIDTH / 2) + POS_X(5)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_J, 'J', 0, ((KEY_WIDTH / 2) + POS_X(6)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_K, 'K', 0, ((KEY_WIDTH / 2) + POS_X(7)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_L, 'L', 0, ((KEY_WIDTH / 2) + POS_X(8)), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, - //Row 3 - {&s_key_caps, 0x14, 0, POS_X(0), POS_Y(2), CAPS_WIDTH, KEY_HEIGHT}, - {&s_key_Z, 'Z', 0, ((KEY_WIDTH / 2) + POS_X(1)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_X, 'X', 0, ((KEY_WIDTH / 2) + POS_X(2)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_C, 'C', 0, ((KEY_WIDTH / 2) + POS_X(3)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_V, 'V', 0, ((KEY_WIDTH / 2) + POS_X(4)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_B, 'B', 0, ((KEY_WIDTH / 2) + POS_X(5)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_N, 'N', 0, ((KEY_WIDTH / 2) + POS_X(6)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_M, 'M', 0, ((KEY_WIDTH / 2) + POS_X(7)), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_del, 0x7F, 0, ((KEY_WIDTH / 2) + POS_X(8)), POS_Y(2), DEL_WIDTH, KEY_HEIGHT}, - //Row 4 - {&s_key_esc, 0x1B, 0, POS_X(0), POS_Y(3), ESC_WIDTH, KEY_HEIGHT}, - {&s_key_num_switch, 0x90, 0, POS_X(2), POS_Y(3), SWITCH_WIDTH, KEY_HEIGHT}, - {&s_key_space, ' ', 0, ((KEY_WIDTH / 2) + POS_X(3)), POS_Y(3), SPACE_WIDTH, KEY_HEIGHT}, - {&s_key_dot, '.', 0, ((KEY_WIDTH / 2) + POS_X(6)), POS_Y(3), DOT_WIDTH, KEY_HEIGHT}, - {&s_key_enter, '\n', 0, POS_X(8), POS_Y(3), ENTER_WIDTH, KEY_HEIGHT}, - {0,0,0,0,0,0,0} -}; -WND_TREE g_number_board_children[] = -{ - {&s_key_1, '1', 0, POS_X(0), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_2, '2', 0, POS_X(1), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_3, '3', 0, POS_X(2), POS_Y(0), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_4, '4', 0, POS_X(0), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_5, '5', 0, POS_X(1), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_6, '6', 0, POS_X(2), POS_Y(1), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_7, '7', 0, POS_X(0), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_8, '8', 0, POS_X(1), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_9, '9', 0, POS_X(2), POS_Y(2), KEY_WIDTH, KEY_HEIGHT}, - - {&s_key_esc, 0x1B, 0, POS_X(0), POS_Y(3), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_0, '0', 0, POS_X(1), POS_Y(3), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_dot, '.', 0, POS_X(2), POS_Y(3), KEY_WIDTH, KEY_HEIGHT}, - {&s_key_del, 0x7F, 0, POS_X(3), POS_Y(0), KEY_WIDTH, KEY_HEIGHT * 2 + 2}, - {&s_key_enter,'\n', 0, POS_X(3), POS_Y(2), KEY_WIDTH, KEY_HEIGHT * 2 + 2}, - {0,0,0,0,0,0,0} -}; -#endif -#pragma GCC diagnostic pop diff --git a/src/lib/lv_conf.h b/src/lib/lv_conf.h new file mode 100644 index 00000000..320f59b0 --- /dev/null +++ b/src/lib/lv_conf.h @@ -0,0 +1,742 @@ +/** + * @file lv_conf.h + * Configuration file for v9.0.0-dev + */ + +/* + * Copy this file as `lv_conf.h` + * 1. simply next to the `lvgl` folder + * 2. or any other places and + * - define `LV_CONF_INCLUDE_SIMPLE` + * - add the path as include path + */ + +/* clang-format off */ +#if 1 /*Set it to "1" to enable content*/ + +#ifndef LV_CONF_H +#define LV_CONF_H + +#include + +/*==================== + COLOR SETTINGS + *====================*/ + +/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/ +#define LV_COLOR_DEPTH 16 + +#define LV_COLOR_CHROMA_KEY lv_color_hex(0x00ff00) + +/*========================= + STDLIB WRAPPER SETTINGS + *=========================*/ + +/*Enable and configure the built-in memory manager*/ +#define LV_USE_BUILTIN_MALLOC 0 +#if LV_USE_BUILTIN_MALLOC + /*Size of the memory available for `lv_malloc()` in bytes (>= 2kB)*/ + #define LV_MEM_SIZE (4U * 1024U) /*[bytes]*/ + + /*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/ + #define LV_MEM_ADR 0 /*0: unused*/ + /*Instead of an address give a memory allocator that will be called to get a memory pool for LVGL. E.g. my_malloc*/ + #if LV_MEM_ADR == 0 + #undef LV_MEM_POOL_INCLUDE + #undef LV_MEM_POOL_ALLOC + #endif +#endif /*LV_USE_BUILTIN_MALLOC*/ + +/*Enable lv_memcpy_builtin, lv_memset_builtin, lv_strlen_builtin, lv_strncpy_builtin*/ +#define LV_USE_BUILTIN_MEMCPY 1 + +/*Enable and configure the built-in (v)snprintf */ +#define LV_USE_BUILTIN_SNPRINTF 1 +#if LV_USE_BUILTIN_SNPRINTF + #define LV_SPRINTF_USE_FLOAT 0 +#endif /*LV_USE_BUILTIN_SNPRINTF*/ + +#define LV_STDLIB_INCLUDE + +#define LV_MALLOC malloc +#define LV_REALLOC realloc +#define LV_FREE free +#define LV_MEMSET lv_memset_builtin +#define LV_MEMCPY lv_memcpy_builtin +#define LV_SNPRINTF lv_snprintf_builtin +#define LV_VSNPRINTF lv_vsnprintf_builtin +#define LV_STRLEN lv_strlen_builtin +#define LV_STRNCPY lv_strncpy_builtin + +/*==================== + HAL SETTINGS + *====================*/ + +/*Use a custom tick source that tells the elapsed time in milliseconds. + *It removes the need to manually update the tick with `lv_tick_inc()`)*/ +#define LV_TICK_CUSTOM 1 +#if LV_TICK_CUSTOM + #define LV_TICK_CUSTOM_INCLUDE "common.h" /*Header for the system time function*/ + #define LV_TICK_CUSTOM_SYS_TIME_EXPR (n64hal_millis()) /*Expression evaluating to current system time in ms*/ +#endif /*LV_TICK_CUSTOM*/ + +/*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings. + *(Not so important, you can adjust it to modify default sizes and spaces)*/ +#define LV_DPI_DEF 130 /*[px/inch]*/ + +/*======================== + * DRAW CONFIGURATION + *========================*/ + +/*Enable the built in mask engine. + *Required to draw shadow, rounded corners, circles, arc, skew lines, or any other masks*/ +#define LV_USE_DRAW_MASKS 0 + +#define LV_USE_DRAW_SW 1 +#if LV_USE_DRAW_SW + + /*Enable complex draw engine. + *Required to draw shadow, gradient, rounded corners, circles, arc, skew lines, image transformations or any masks*/ + #define LV_DRAW_SW_COMPLEX 0 + + /* If a widget has `style_opa < 255` (not `bg_opa`, `text_opa` etc) or not NORMAL blend mode + * it is buffered into a "simple" layer before rendering. The widget can be buffered in smaller chunks. + * "Transformed layers" (if `transform_angle/zoom` are set) use larger buffers + * and can't be drawn in chunks. */ + + /*The target buffer size for simple layer chunks.*/ + #define LV_DRAW_SW_LAYER_SIMPLE_BUF_SIZE (24 * 1024) /*[bytes]*/ + + /*Used if `LV_DRAW_SW_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated.*/ + #define LV_DRAW_SW_LAYER_SIMPLE_FALLBACK_BUF_SIZE (3 * 1024) /*[bytes]*/ + + /*Allow buffering some shadow calculation. + *LV_DRAW_SW_SHADOW_CACHE_SIZE is the max. shadow size to buffer, where shadow size is `shadow_width + radius` + *Caching has LV_DRAW_SW_SHADOW_CACHE_SIZE^2 RAM cost*/ + #define LV_DRAW_SW_SHADOW_CACHE_SIZE 0 + + /* Set number of maximally cached circle data. + * The circumference of 1/4 circle are saved for anti-aliasing + * radius * 4 bytes are used per circle (the most often used radiuses are saved) + * 0: to disable caching */ + #define LV_DRAW_SW_CIRCLE_CACHE_SIZE 0 + + /*Default gradient buffer size. + *When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again. + *LV_DRAW_SW_GRADIENT_CACHE_DEF_SIZE sets the size of this cache in bytes. + *If the cache is too small the map will be allocated only while it's required for the drawing. + *0 mean no caching.*/ + #define LV_DRAW_SW_GRADIENT_CACHE_DEF_SIZE 0 + + /*Allow dithering the gradients (to achieve visual smooth color gradients on limited color depth display) + *LV_DRAW_SW_GRADIENT_DITHER implies allocating one or two more lines of the object's rendering surface + *The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */ + #define LV_DRAW_SW_GRADIENT_DITHER 0 + #if LV_DRAW_SW_GRADIENT_DITHER + /*Add support for error diffusion dithering. + *Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing. + *The increase in memory consumption is (24 bits * object's width)*/ + #define LV_DRAW_SW_GRADIENT_DITHER_ERROR_DIFFUSION 0 + #endif + + /*Enable subpixel rendering*/ + #define LV_DRAW_SW_FONT_SUBPX 0 + #if LV_DRAW_SW_FONT_SUBPX + /*Set the pixel order of the display. Physical order of RGB channels. Doesn't matter with "normal" fonts.*/ + #define LV_DRAW_SW_FONT_SUBPX_BGR 0 /*0: RGB; 1:BGR order*/ + #endif +#endif + +/*Use SDL renderer API*/ +#define LV_USE_DRAW_SDL 0 +#if LV_USE_DRAW_SDL + #define LV_DRAW_SDL_INCLUDE_PATH + /*Texture cache size, 8MB by default*/ + #define LV_DRAW_SDL_LRU_SIZE (1024 * 1024 * 8) + /*Custom blend mode for mask drawing, disable if you need to link with older SDL2 lib*/ + #define LV_DRAW_SDL_CUSTOM_BLEND_MODE (SDL_VERSION_ATLEAST(2, 0, 6)) +#endif + +/*===================== + * GPU CONFIGURATION + *=====================*/ + +/*Use Arm's 2D acceleration library Arm-2D */ +#define LV_USE_GPU_ARM2D 0 + +/*Use STM32's DMA2D (aka Chrom Art) GPU*/ +#define LV_USE_GPU_STM32_DMA2D 0 +#if LV_USE_GPU_STM32_DMA2D + /*Must be defined to include path of CMSIS header of target processor + e.g. "stm32f769xx.h" or "stm32f429xx.h"*/ + #define LV_GPU_DMA2D_CMSIS_INCLUDE +#endif + +/*Use NXP's PXP GPU iMX RTxxx platforms*/ +#define LV_USE_GPU_NXP_PXP 0 +#if LV_USE_GPU_NXP_PXP + /*1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c) + * and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol SDK_OS_FREE_RTOS + * has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected. + *0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init() + */ + #define LV_USE_GPU_NXP_PXP_AUTO_INIT 0 +#endif + +/*Use NXP's VG-Lite GPU iMX RTxxx platforms*/ +#define LV_USE_GPU_NXP_VG_LITE 0 + +/*Use SWM341's DMA2D GPU*/ +#define LV_USE_GPU_SWM341_DMA2D 0 +#if LV_USE_GPU_SWM341_DMA2D + #define LV_GPU_SWM341_DMA2D_INCLUDE "SWM341.h" +#endif + +/*======================= + * FEATURE CONFIGURATION + *=======================*/ + +/*------------- + * Logging + *-----------*/ + +/*Enable the log module*/ +#define LV_USE_LOG 1 +#if LV_USE_LOG + + /*How important log should be added: + *LV_LOG_LEVEL_TRACE A lot of logs to give detailed information + *LV_LOG_LEVEL_INFO Log important events + *LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem + *LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail + *LV_LOG_LEVEL_USER Only logs added by the user + *LV_LOG_LEVEL_NONE Do not log anything*/ + #define LV_LOG_LEVEL LV_LOG_LEVEL_WARN + + /*1: Print the log with 'printf'; + *0: User need to register a callback with `lv_log_register_print_cb()`*/ + #define LV_LOG_PRINTF 0 + + /*Enable/disable LV_LOG_TRACE in modules that produces a huge number of logs*/ + #define LV_LOG_TRACE_MEM 1 + #define LV_LOG_TRACE_TIMER 1 + #define LV_LOG_TRACE_INDEV 1 + #define LV_LOG_TRACE_DISP_REFR 1 + #define LV_LOG_TRACE_EVENT 1 + #define LV_LOG_TRACE_OBJ_CREATE 1 + #define LV_LOG_TRACE_LAYOUT 1 + #define LV_LOG_TRACE_ANIM 1 + +#endif /*LV_USE_LOG*/ + +/*------------- + * Asserts + *-----------*/ + +/*Enable asserts if an operation is failed or an invalid data is found. + *If LV_USE_LOG is enabled an error message will be printed on failure*/ +#define LV_USE_ASSERT_NULL 1 /*Check if the parameter is NULL. (Very fast, recommended)*/ +#define LV_USE_ASSERT_MALLOC 1 /*Checks is the memory is successfully allocated or no. (Very fast, recommended)*/ +#define LV_USE_ASSERT_STYLE 0 /*Check if the styles are properly initialized. (Very fast, recommended)*/ +#define LV_USE_ASSERT_MEM_INTEGRITY 0 /*Check the integrity of `lv_mem` after critical operations. (Slow)*/ +#define LV_USE_ASSERT_OBJ 0 /*Check the object's type and existence (e.g. not deleted). (Slow)*/ + +/*Add a custom handler when assert happens e.g. to restart the MCU*/ +#define LV_ASSERT_HANDLER_INCLUDE +#define LV_ASSERT_HANDLER while(1); /*Halt by default*/ + +/*------------- + * Others + *-----------*/ + +/*1: Show CPU usage and FPS count*/ +#define LV_USE_PERF_MONITOR 0 +#if LV_USE_PERF_MONITOR + #define LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT +#endif + +/*1: Show the used memory and the memory fragmentation + * Requires `LV_USE_BUILTIN_MALLOC = 1`*/ +#define LV_USE_MEM_MONITOR 0 +#if LV_USE_MEM_MONITOR + #define LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_LEFT +#endif + +/*1: Draw random colored rectangles over the redrawn areas*/ +#define LV_USE_REFR_DEBUG 0 + +/*Maximum buffer size to allocate for rotation. + *Only used if software rotation is enabled in the display driver.*/ +#define LV_DISP_ROT_MAX_BUF (10*1024) + +#define LV_USE_USER_DATA 1 + +/*Garbage Collector settings + *Used if lvgl is bound to higher level language and the memory is managed by that language*/ +#define LV_ENABLE_GC 0 +#if LV_ENABLE_GC != 0 + #define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/ +#endif /*LV_ENABLE_GC*/ + +/*Default image cache size. Image caching keeps some images opened. + *If only the built-in image formats are used there is no real advantage of caching. + *With other image decoders (e.g. PNG or JPG) caching save the continuous open/decode of images. + *However the opened images consume additional RAM. + *0: to disable caching*/ +#define LV_IMG_CACHE_DEF_SIZE 4 + + +/*Number of stops allowed per gradient. Increase this to allow more stops. + *This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/ +#define LV_GRADIENT_MAX_STOPS 2 + +/* Adjust color mix functions rounding. GPUs might calculate color mix (blending) differently. + * 0: round down, 64: round up from x.75, 128: round up from half, 192: round up from x.25, 254: round up */ +#define LV_COLOR_MIX_ROUND_OFS 0 + +/*===================== + * COMPILER SETTINGS + *====================*/ + +/*For big endian systems set to 1*/ +#define LV_BIG_ENDIAN_SYSTEM 0 + +/*Define a custom attribute to `lv_tick_inc` function*/ +#define LV_ATTRIBUTE_TICK_INC + +/*Define a custom attribute to `lv_timer_handler` function*/ +#define LV_ATTRIBUTE_TIMER_HANDLER + +/*Define a custom attribute to `lv_disp_flush_ready` function*/ +#define LV_ATTRIBUTE_FLUSH_READY + +/*Required alignment size for buffers*/ +#define LV_ATTRIBUTE_MEM_ALIGN_SIZE 1 + +/*Will be added where memories needs to be aligned (with -Os data might not be aligned to boundary by default). + * E.g. __attribute__((aligned(4)))*/ +#define LV_ATTRIBUTE_MEM_ALIGN + +/*Attribute to mark large constant arrays for example font's bitmaps*/ +#define LV_ATTRIBUTE_LARGE_CONST + +/*Compiler prefix for a big array declaration in RAM*/ +#define LV_ATTRIBUTE_LARGE_RAM_ARRAY + +/*Place performance critical functions into a faster memory (e.g RAM)*/ +#define LV_ATTRIBUTE_FAST_MEM + + +/*Export integer constant to binding. This macro is used with constants in the form of LV_ that + *should also appear on LVGL binding API such as Micropython.*/ +#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning /*The default value just prevents GCC warning*/ + +/*Extend the default -32k..32k coordinate range to -4M..4M by using int32_t for coordinates instead of int16_t*/ +#define LV_USE_LARGE_COORD 0 + +/*================== + * FONT USAGE + *===================*/ + +/*Montserrat fonts with ASCII range and some symbols using bpp = 4 + *https://fonts.google.com/specimen/Montserrat*/ +#define LV_FONT_MONTSERRAT_8 0 +#define LV_FONT_MONTSERRAT_10 1 +#define LV_FONT_MONTSERRAT_12 0 +#define LV_FONT_MONTSERRAT_14 0 +#define LV_FONT_MONTSERRAT_16 0 +#define LV_FONT_MONTSERRAT_18 1 +#define LV_FONT_MONTSERRAT_20 0 +#define LV_FONT_MONTSERRAT_22 0 +#define LV_FONT_MONTSERRAT_24 0 +#define LV_FONT_MONTSERRAT_26 0 +#define LV_FONT_MONTSERRAT_28 0 +#define LV_FONT_MONTSERRAT_30 0 +#define LV_FONT_MONTSERRAT_32 0 +#define LV_FONT_MONTSERRAT_34 0 +#define LV_FONT_MONTSERRAT_36 0 +#define LV_FONT_MONTSERRAT_38 0 +#define LV_FONT_MONTSERRAT_40 0 +#define LV_FONT_MONTSERRAT_42 0 +#define LV_FONT_MONTSERRAT_44 0 +#define LV_FONT_MONTSERRAT_46 0 +#define LV_FONT_MONTSERRAT_48 0 + +/*Demonstrate special features*/ +#define LV_FONT_MONTSERRAT_12_SUBPX 0 +#define LV_FONT_MONTSERRAT_28_COMPRESSED 0 /*bpp = 3*/ +#define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 /*Hebrew, Arabic, Persian letters and all their forms*/ +#define LV_FONT_SIMSUN_16_CJK 0 /*1000 most common CJK radicals*/ + +/*Pixel perfect monospace fonts*/ +#define LV_FONT_UNSCII_8 0 +#define LV_FONT_UNSCII_16 0 + +/*Optionally declare custom fonts here. + *You can use these fonts as default font too and they will be available globally. + *E.g. #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) LV_FONT_DECLARE(my_font_2)*/ +#define LV_FONT_CUSTOM_DECLARE + +/*Always set a default font*/ +#define LV_FONT_DEFAULT &lv_font_montserrat_10 + +/*Enable handling large font and/or fonts with a lot of characters. + *The limit depends on the font size, font face and bpp. + *Compiler error will be triggered if a font needs it.*/ +#define LV_FONT_FMT_TXT_LARGE 0 + +/*Enables/disables support for compressed fonts.*/ +#define LV_USE_FONT_COMPRESSED 0 + +/*Enable drawing placeholders when glyph dsc is not found*/ +#define LV_USE_FONT_PLACEHOLDER 1 + +/*================= + * TEXT SETTINGS + *=================*/ + +/** + * Select a character encoding for strings. + * Your IDE or editor should have the same character encoding + * - LV_TXT_ENC_UTF8 + * - LV_TXT_ENC_ASCII + */ +#define LV_TXT_ENC LV_TXT_ENC_UTF8 + +/*Can break (wrap) texts on these chars*/ +#define LV_TXT_BREAK_CHARS " ,.;:-_" + +/*If a word is at least this long, will break wherever "prettiest" + *To disable, set to a value <= 0*/ +#define LV_TXT_LINE_BREAK_LONG_LEN 0 + +/*Minimum number of characters in a long word to put on a line before a break. + *Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/ +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 + +/*Minimum number of characters in a long word to put on a line after a break. + *Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/ +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 + +/*The control character to use for signalling text recoloring.*/ +#define LV_TXT_COLOR_CMD "#" + +/*Support bidirectional texts. Allows mixing Left-to-Right and Right-to-Left texts. + *The direction will be processed according to the Unicode Bidirectional Algorithm: + *https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/ +#define LV_USE_BIDI 0 +#if LV_USE_BIDI + /*Set the default direction. Supported values: + *`LV_BASE_DIR_LTR` Left-to-Right + *`LV_BASE_DIR_RTL` Right-to-Left + *`LV_BASE_DIR_AUTO` detect texts base direction*/ + #define LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO +#endif + +/*Enable Arabic/Persian processing + *In these languages characters should be replaced with an other form based on their position in the text*/ +#define LV_USE_ARABIC_PERSIAN_CHARS 0 + +/*================== + * WIDGETS + *================*/ + +/*Documentation of the widgets: https://docs.lvgl.io/latest/en/html/widgets/index.html*/ + +#define LV_USE_ANIMIMG 0 + +#define LV_USE_ARC 0 + +#define LV_USE_BAR 0 + +#define LV_USE_BTN 0 + +#define LV_USE_BTNMATRIX 0 + +#define LV_USE_CALENDAR 0 +#if LV_USE_CALENDAR + #define LV_CALENDAR_WEEK_STARTS_MONDAY 0 + #if LV_CALENDAR_WEEK_STARTS_MONDAY + #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"} + #else + #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"} + #endif + + #define LV_CALENDAR_DEFAULT_MONTH_NAMES {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} + #define LV_USE_CALENDAR_HEADER_ARROW 1 + #define LV_USE_CALENDAR_HEADER_DROPDOWN 1 +#endif /*LV_USE_CALENDAR*/ + +#define LV_USE_CANVAS 1 + +#define LV_USE_CHART 0 + +#define LV_USE_CHECKBOX 0 + +#define LV_USE_COLORWHEEL 0 + +#define LV_USE_DROPDOWN 0 /*Requires: lv_label*/ + +#define LV_USE_IMG 1 /*Requires: lv_label*/ + +#define LV_USE_IMGBTN 0 + +#define LV_USE_KEYBOARD 0 + +#define LV_USE_LABEL 1 +#if LV_USE_LABEL + #define LV_LABEL_TEXT_SELECTION 1 /*Enable selecting text of the label*/ + #define LV_LABEL_LONG_TXT_HINT 1 /*Store some extra info in labels to speed up drawing of very long texts*/ +#endif + +#define LV_USE_LED 0 + +#define LV_USE_LINE 0 + +#define LV_USE_LIST 0 + +#define LV_USE_MENU 0 + +#define LV_USE_METER 0 + +#define LV_USE_MSGBOX 0 + +#define LV_USE_ROLLER 0 /*Requires: lv_label*/ +#if LV_USE_ROLLER + #define LV_ROLLER_INF_PAGES 7 /*Number of extra "pages" when the roller is infinite*/ +#endif + +#define LV_USE_SLIDER 0 /*Requires: lv_bar*/ + +#define LV_USE_SPAN 0 +#if LV_USE_SPAN + /*A line text can contain maximum num of span descriptor */ + #define LV_SPAN_SNIPPET_STACK_SIZE 64 +#endif + +#define LV_USE_SPINBOX 0 + +#define LV_USE_SPINNER 0 + +#define LV_USE_SWITCH 0 + +#define LV_USE_TEXTAREA 0 /*Requires: lv_label*/ +#if LV_USE_TEXTAREA != 0 + #define LV_TEXTAREA_DEF_PWD_SHOW_TIME 1500 /*ms*/ +#endif + +#define LV_USE_TABLE 0 + +#define LV_USE_TABVIEW 0 + +#define LV_USE_TILEVIEW 0 + +#define LV_USE_WIN 0 + +/*================== + * THEMES + *==================*/ + +/*A simple, impressive and very complete theme*/ +#define LV_USE_THEME_DEFAULT 1 +#if LV_USE_THEME_DEFAULT + + /*0: Light mode; 1: Dark mode*/ + #define LV_THEME_DEFAULT_DARK 1 + + /*1: Enable grow on press*/ + #define LV_THEME_DEFAULT_GROW 1 + + /*Default transition time in [ms]*/ + #define LV_THEME_DEFAULT_TRANSITION_TIME 20 +#endif /*LV_USE_THEME_DEFAULT*/ + +/*A very simple theme that is a good starting point for a custom theme*/ +#define LV_USE_THEME_BASIC 0 + +/*A theme designed for monochrome displays*/ +#define LV_USE_THEME_MONO 0 + +/*================== + * LAYOUTS + *==================*/ + +/*A layout similar to Flexbox in CSS.*/ +#define LV_USE_FLEX 1 + +/*A layout similar to Grid in CSS.*/ +#define LV_USE_GRID 0 + +/*==================== + * 3RD PARTS LIBRARIES + *====================*/ + +/*File system interfaces for common APIs */ + +/*API for fopen, fread, etc*/ +#define LV_USE_FS_STDIO 0 +#if LV_USE_FS_STDIO + #define LV_FS_STDIO_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_STDIO_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ + #define LV_FS_STDIO_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ +#endif + +/*API for open, read, etc*/ +#define LV_USE_FS_POSIX 0 +#if LV_USE_FS_POSIX + #define LV_FS_POSIX_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_POSIX_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ + #define LV_FS_POSIX_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ +#endif + +/*API for CreateFile, ReadFile, etc*/ +#define LV_USE_FS_WIN32 0 +#if LV_USE_FS_WIN32 + #define LV_FS_WIN32_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_WIN32_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ + #define LV_FS_WIN32_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ +#endif + +/*API for FATFS (needs to be added separately). Uses f_open, f_read, etc*/ +#define LV_USE_FS_FATFS 0 +#if LV_USE_FS_FATFS + #define LV_FS_FATFS_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_FATFS_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ +#endif + +/*PNG decoder library*/ +#define LV_USE_PNG 0 + +/*BMP decoder library*/ +#define LV_USE_BMP 0 + +/* JPG + split JPG decoder library. + * Split JPG is a custom format optimized for embedded systems. */ +#define LV_USE_SJPG 0 + +/*GIF decoder library*/ +#define LV_USE_GIF 0 + +/*QR code library*/ +#define LV_USE_QRCODE 0 + +/*FreeType library*/ +#define LV_USE_FREETYPE 0 +#if LV_USE_FREETYPE + /*Memory used by FreeType to cache characters [bytes] (-1: no caching)*/ + #define LV_FREETYPE_CACHE_SIZE (16 * 1024) + #if LV_FREETYPE_CACHE_SIZE >= 0 + /* 1: bitmap cache use the sbit cache, 0:bitmap cache use the image cache. */ + /* sbit cache:it is much more memory efficient for small bitmaps(font size < 256) */ + /* if font size >= 256, must be configured as image cache */ + #define LV_FREETYPE_SBIT_CACHE 0 + /* Maximum number of opened FT_Face/FT_Size objects managed by this cache instance. */ + /* (0:use system defaults) */ + #define LV_FREETYPE_CACHE_FT_FACES 0 + #define LV_FREETYPE_CACHE_FT_SIZES 0 + #endif +#endif + +/*Rlottie library*/ +#define LV_USE_RLOTTIE 0 + +/*FFmpeg library for image decoding and playing videos + *Supports all major image formats so do not enable other image decoder with it*/ +#define LV_USE_FFMPEG 0 +#if LV_USE_FFMPEG + /*Dump input information to stderr*/ + #define LV_FFMPEG_DUMP_FORMAT 0 +#endif + +/*================== + * OTHERS + *==================*/ + +/*1: Enable API to take snapshot for object*/ +#define LV_USE_SNAPSHOT 0 + +/*1: Enable Monkey test*/ +#define LV_USE_MONKEY 0 + +/*1: Enable grid navigation*/ +#define LV_USE_GRIDNAV 0 + +/*1: Enable lv_obj fragment*/ +#define LV_USE_FRAGMENT 0 + +/*1: Support using images as font in label or span widgets */ +#define LV_USE_IMGFONT 0 +#if LV_USE_IMGFONT + /*Imgfont image file path maximum length*/ + #define LV_IMGFONT_PATH_MAX_LEN 64 + + /*1: Use img cache to buffer header information*/ + #define LV_IMGFONT_USE_IMG_CACHE_HEADER 0 +#endif + +/*1: Enable a published subscriber based messaging system */ +#define LV_USE_MSG 0 + +/*1: Enable Pinyin input method*/ +/*Requires: lv_keyboard*/ +#define LV_USE_IME_PINYIN 0 +#if LV_USE_IME_PINYIN + /*1: Use default thesaurus*/ + /*If you do not use the default thesaurus, be sure to use `lv_ime_pinyin` after setting the thesauruss*/ + #define LV_IME_PINYIN_USE_DEFAULT_DICT 1 + /*Set the maximum number of candidate panels that can be displayed*/ + /*This needs to be adjusted according to the size of the screen*/ + #define LV_IME_PINYIN_CAND_TEXT_NUM 6 + + /*Use 9 key input(k9)*/ + #define LV_IME_PINYIN_USE_K9_MODE 1 + #if LV_IME_PINYIN_USE_K9_MODE == 1 + #define LV_IME_PINYIN_K9_CAND_TEXT_NUM 3 + #endif // LV_IME_PINYIN_USE_K9_MODE +#endif + +/*================== +* EXAMPLES +*==================*/ + +/*Enable the examples to be built with the library*/ +#define LV_BUILD_EXAMPLES 0 + +/*=================== + * DEMO USAGE + ====================*/ + +/*Show some widget. It might be required to increase `LV_MEM_SIZE` */ +#define LV_USE_DEMO_WIDGETS 0 +#if LV_USE_DEMO_WIDGETS + #define LV_DEMO_WIDGETS_SLIDESHOW 0 +#endif + +/*Demonstrate the usage of encoder and keyboard*/ +#define LV_USE_DEMO_KEYPAD_AND_ENCODER 0 + +/*Benchmark your system*/ +#define LV_USE_DEMO_BENCHMARK 0 +#if LV_USE_DEMO_BENCHMARK + /*Use RGB565A8 images with 16 bit color depth instead of ARGB8565*/ + #define LV_DEMO_BENCHMARK_RGB565A8 0 +#endif + +/*Stress test for LVGL*/ +#define LV_USE_DEMO_STRESS 0 + +/*Music player demo*/ +#define LV_USE_DEMO_MUSIC 0 +#if LV_USE_DEMO_MUSIC + #define LV_DEMO_MUSIC_SQUARE 0 + #define LV_DEMO_MUSIC_LANDSCAPE 0 + #define LV_DEMO_MUSIC_ROUND 0 + #define LV_DEMO_MUSIC_LARGE 0 + #define LV_DEMO_MUSIC_AUTO_PLAY 0 +#endif + +/*--END OF LV_CONF_H--*/ + +#endif /*LV_CONF_H*/ + +#endif /*End of "Content enable"*/ \ No newline at end of file diff --git a/src/lib/lvgl b/src/lib/lvgl new file mode 160000 index 00000000..dfd14fa7 --- /dev/null +++ b/src/lib/lvgl @@ -0,0 +1 @@ +Subproject commit dfd14fa778aef25d0db61748a58aa9989ce5e2c8 diff --git a/src/main.cpp b/src/main.cpp index 6098e4ee..3cc16e00 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -92,12 +92,18 @@ void loop() input_update_input_devices(); - tft_try_update(); + tft_update(); for (uint32_t c = 0; c < MAX_CONTROLLERS; c++) { if (input_is_connected(c)) { + if (n64_in_dev[c].connected == 0) + { + n64_in_dev[c].connected = 1; + tft_flag_update(c); + } + if (n64_is_on && !n64_in_dev[c].interrupt_attached) { switch (c) @@ -108,7 +114,7 @@ void loop() case 3: n64hal_attach_interrupt(n64_in_dev[c].pin, n64_controller4_clock_edge, N64_INTMODE_FALLING); break; } n64_in_dev[c].interrupt_attached = true; - tft_flag_update(); + tft_flag_update(c); } if (input_is(c, INPUT_GAMECONTROLLER)) { @@ -118,7 +124,7 @@ void loop() if(n64_in_dev[c].type != N64_CONTROLLER) { n64_in_dev[c].type = N64_CONTROLLER; - tft_flag_update(); + tft_flag_update(c); } n64_settings *settings = n64_settings_get(); float x, y, range; @@ -158,7 +164,7 @@ void loop() if(n64_in_dev[c].type != N64_MOUSE) { n64_in_dev[c].type = N64_MOUSE; - tft_flag_update(); + tft_flag_update(c); } n64_in_dev[c].b_state.dButtons = new_state->dButtons; n64_in_dev[c].b_state.x_axis = new_state->x_axis; @@ -177,18 +183,26 @@ void loop() if(n64_in_dev[c].type != N64_RANDNET) { n64_in_dev[c].type = N64_RANDNET; - tft_flag_update(); + tft_flag_update(c); } memcpy(&n64_in_dev[c].kb_state, new_state, sizeof(n64_randnet_kb)); } #endif } + else + { + if (n64_in_dev[c].connected == 1) + { + n64_in_dev[c].connected = 0; + tft_flag_update(c); + } + } if ((!input_is_connected(c) || !n64_is_on) && n64_in_dev[c].interrupt_attached) { n64_in_dev[c].interrupt_attached = false; n64hal_detach_interrupt(n64_in_dev[c].pin); - tft_flag_update(); + tft_flag_update(c); } //Get a copy of the latest n64 button presses to handle the below combos @@ -237,12 +251,12 @@ void loop() memory_flush_all(); debug_print_status("[MAIN] Flushed RAM to SD card as required\n"); flushing_toggle[c] = 1; - tft_flag_update(); + tft_flag_update(c); } } else { - if (flushing_toggle[c]) tft_flag_update(); + if (flushing_toggle[c]) tft_flag_update(c); flushing_toggle[c] = 0; } @@ -256,7 +270,7 @@ void loop() { tft_page = tft_change_page(++tft_page); tft_toggle[c] = 1; - tft_flag_update(); + tft_flag_update(c); } } else @@ -312,7 +326,7 @@ void loop() /* HANDLE NEXT PERIPHERAL */ n64_in_dev[c].current_peripheral = PERI_NONE; //Go to none whilst changing - tft_force_update(); + tft_update(); //Changing peripheral to RUMBLEPAK if (n64_buttons & N64_LB) @@ -435,7 +449,7 @@ void loop() if (n64_in_dev[c].current_peripheral == PERI_NONE && (n64hal_millis() - timer_peri_change[c]) > PERI_CHANGE_TIME) { n64_in_dev[c].current_peripheral = n64_in_dev[c].next_peripheral; - tft_flag_update(); + tft_flag_update(c); } //Update the virtual pak if required @@ -483,5 +497,6 @@ static void ring_buffer_flush() tft_add_log(ring_buffer[_print_cursor]); ring_buffer[_print_cursor] = 0xFF; _print_cursor = (_print_cursor + 1) % sizeof(ring_buffer); + tft_flag_update(0xFF); } } diff --git a/src/n64/n64_controller.h b/src/n64/n64_controller.h index ad5c99e8..f857b81e 100644 --- a/src/n64/n64_controller.h +++ b/src/n64/n64_controller.h @@ -61,6 +61,7 @@ typedef struct n64_rumblepak *rpak; //Pointer to installed rumblepak n64_controllerpak *cpak; //Pointer to installed controllerpak // + uint8_t connected; //Flag is set when this controller is connected uint32_t interrupt_attached; //Flag is set when this controller is connected to an ext int. uint32_t bus_idle_timer_clks; //Timer counter for bus idle timing usb64_pin_t pin; //What pin is this controller connected to diff --git a/src/port_teensy41/hal_t4.cpp b/src/port_teensy41/hal_t4.cpp index 11f1ca14..7cf569bc 100644 --- a/src/port_teensy41/hal_t4.cpp +++ b/src/port_teensy41/hal_t4.cpp @@ -15,6 +15,7 @@ void n64hal_system_init() void n64hal_debug_init() { serial_port.begin(256000); + serial_port.print(CrashReport); } void n64hal_gpio_init() diff --git a/src/port_teensy41/tft_t4.cpp b/src/port_teensy41/tft_t4.cpp index 4f641072..03ed57ae 100644 --- a/src/port_teensy41/tft_t4.cpp +++ b/src/port_teensy41/tft_t4.cpp @@ -3,84 +3,31 @@ #include #include "common.h" +#include "printf.h" #include "controller_icon.h" #include "usb64_logo.h" -#include "GuiLite.h" - -c_surface *psurface_guilite = NULL; -c_display *pdisplay_guilite = NULL; -#if TFT_USE_FRAMEBUFFER -static DMAMEM uint8_t _framebuffer[TFT_WIDTH * TFT_HEIGHT * TFT_PIXEL_SIZE]; -#else -struct EXTERNAL_GFX_OP my_gfx_op; -#endif +#include "lvgl.h" #include "ILI9341_t3n.h" -static ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO); - -static void _tft_assert(const char *file, int line) -{ - debug_print_error("[TFT] Error: Assert in %s on line %d\n", file, line); - while (1) - ; -} - -static void _tft_log_out(const char *log) -{ - debug_print_status(log); -} -#if TFT_USE_FRAMEBUFFER == 0 -/* - * Function: Draw a pixel to your display at a given coordinate. Required if NOT using a framebuffer - * ---------------------------- - * Returns: Void - * - * x: horizontal pixel position - * y: vertical pixel position - * rgb: RGB888 colour. You can use GL_RGB_32_to_16 to convert to RGB565 if needed. - */ -static void _draw_pixel(int x, int y, unsigned int rgb) -{ - tft.drawPixel(x, y, GL_RGB_32_to_16(rgb)); -} +static ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO); +static lv_disp_drv_t disp_drv; +static lv_disp_draw_buf_t draw_buf; +static DMAMEM uint8_t _framebuffer[TFT_WIDTH * TFT_HEIGHT * TFT_PIXEL_SIZE]; -/* - * Function: Fill a given rectangle area. Required if NOT using a framebuffer - * ---------------------------- - * Returns: Void - * - * x0,y0: Top left rectangle pixel position - * x1,y1: Bottom right pixel position - * rgb: RGB888 colour. You can use GL_RGB_32_to_16 to convert to RGB565 if needed. - */ -static void _fill_rect(int x0, int y0, int x1, int y1, unsigned int rgb) +//LVGL Callback that should update the LCD +static void disp_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) { - tft.fillRect(x0, y0, x1 - x0, y1 - y0, GL_RGB_32_to_16(rgb)); + tft.updateScreenAsync(); } -#endif -/* - * Function: Start TFT draw. Required if using a framebuffer. This should draw the framebuffer to the screen using DMA or similar. - * ---------------------------- - * Returns: Void - * - * force: If force is true, you must wait for any previous screen updates to finished then update. - */ -void tft_dev_draw(bool force) +//LVGL Callback that will be called whilse the LCD is updating +static void disp_wait(lv_disp_drv_t *disp_drv) { -#if TFT_USE_FRAMEBUFFER - if (force) - { - while (tft.asyncUpdateActive()); - tft.updateScreenAsync(); - } - else if (tft.asyncUpdateActive()) + if (tft.asyncUpdateActive() == false) { - return; + lv_disp_flush_ready(disp_drv); } - -#endif } /* @@ -92,23 +39,24 @@ void tft_dev_init() { tft.begin(); tft.setRotation(TFT_ROTATION); -#if TFT_USE_FRAMEBUFFER - static c_surface surface(TFT_WIDTH, TFT_HEIGHT, 2, Z_ORDER_LEVEL_0); - static c_display display(_framebuffer, TFT_WIDTH, TFT_HEIGHT, &surface); tft.setFrameBuffer((uint16_t *)_framebuffer); tft.useFrameBuffer(true); -#else - static c_surface_no_fb surface(TFT_WIDTH, TFT_HEIGHT, 2, &my_gfx_op, Z_ORDER_LEVEL_0); - static c_display display(NULL, TFT_WIDTH, TFT_HEIGHT, &surface); - my_gfx_op.draw_pixel = _draw_pixel; - my_gfx_op.fill_rect = _fill_rect; -#endif - psurface_guilite = &surface; - pdisplay_guilite = &display; - register_debug_function(_tft_assert, _tft_log_out); -} - -bool tft_dev_is_busy() -{ - return tft.asyncUpdateActive(); + tft.fillScreen(0x10A2); + tft.updateScreen(); + + lv_disp_draw_buf_init(&draw_buf, _framebuffer, NULL, TFT_WIDTH * TFT_HEIGHT); + lv_disp_drv_init(&disp_drv); + + disp_drv.hor_res = TFT_WIDTH; + disp_drv.ver_res = TFT_HEIGHT; + disp_drv.flush_cb = disp_flush; + disp_drv.wait_cb = disp_wait; + disp_drv.draw_buf = &draw_buf; + disp_drv.direct_mode = 1; + disp_drv.antialiasing = 0; + + lv_disp_drv_register(&disp_drv); + lv_disp_t * disp = lv_disp_get_default(); + lv_timer_set_period(disp->refr_timer, 100); + return; } diff --git a/src/tft.cpp b/src/tft.cpp index 3b9d1551..73b508d0 100644 --- a/src/tft.cpp +++ b/src/tft.cpp @@ -8,39 +8,34 @@ #include "tft.h" #include "fileio.h" -#define GUILITE_ON -#include "GuiLite.h" - +#include "lvgl.h" #include "controller_icon.h" #include "usb64_logo.h" static const int WIDTH = TFT_FRAMEBUFFER_WIDTH; static const int HEIGHT = TFT_FRAMEBUFFER_HEIGHT; static uint8_t _tft_page = 0; -static uint8_t _tft_page_changed = 1; -static uint8_t _tft_max_pages = 2; -static uint8_t _tft_update_needed = 0; +static const uint8_t _tft_max_pages = 2; static const uint8_t _tft_log_max_lines = 15; static char *_tft_log_text_lines[_tft_log_max_lines]; extern n64_input_dev_t n64_in_dev[MAX_CONTROLLERS]; extern n64_transferpak n64_tpak[MAX_CONTROLLERS]; - extern n64_input_dev_t n64_in_dev[MAX_CONTROLLERS]; extern n64_transferpak n64_tpak[MAX_CONTROLLERS]; -static char text_buff[32]; - -extern const LATTICE_FONT_INFO Arial_14_GL; -extern const LATTICE_FONT_INFO Arial_19_GL; -extern c_surface *psurface_guilite; -static c_label n64_status; -static c_label fileio_status; -static c_label extram_size; -static c_label controller_status[4]; -static c_label controller_id[4]; -static c_label tft_log[_tft_log_max_lines]; +static bool input_dirty[MAX_CONTROLLERS]; +static bool log_dirty = true; +static bool n64_status; +static lv_obj_t *log_page; +static lv_obj_t *log_lines[_tft_log_max_lines]; +static lv_obj_t *main_page; +static lv_obj_t *ram_label; +static lv_obj_t *sd_label; +static lv_obj_t *n64_status_label; +static lv_obj_t *controller_status_label[4]; +static const char *NOT_CONNECTED = "NOT CONNECTED\n0x0000/0x0000"; static const char *n64_peri_to_string(n64_input_dev_t *c) { @@ -86,202 +81,179 @@ static const char *n64_peri_to_string(n64_input_dev_t *c) } } +void lvgl_putstring(const char *buf) +{ + usb64_printf("%s", buf); +} + FLASHMEM void tft_init() { + lv_init(); + lv_log_register_print_cb(lvgl_putstring); tft_dev_init(); - if (psurface_guilite == NULL) + lv_obj_t *scr = lv_scr_act(); + + lv_obj_t *usb64_image = lv_canvas_create(scr); + lv_canvas_set_buffer(usb64_image, (void *)usb64_logo, 120, 35, LV_IMG_CF_TRUE_COLOR); + lv_obj_update_layout(usb64_image); + + main_page = lv_obj_create(scr); + lv_obj_set_size(main_page, lv_obj_get_width(scr), lv_obj_get_height(scr) - lv_obj_get_height(usb64_image)); + lv_obj_set_style_pad_all(main_page, 0, LV_PART_MAIN); + lv_obj_set_style_border_width(main_page, 0, LV_PART_MAIN); + lv_obj_set_style_bg_color(main_page, LV_COLOR_MAKE(17,20,16), LV_PART_MAIN); + lv_obj_set_pos(main_page, 0, lv_obj_get_height(usb64_image)); + + log_page = lv_obj_create(scr); + lv_obj_set_size(log_page, lv_obj_get_width(scr), lv_obj_get_height(scr) - lv_obj_get_height(usb64_image)); + lv_obj_set_style_pad_all(log_page, 0, LV_PART_MAIN); + lv_obj_set_style_pad_row(log_page, 0, LV_PART_MAIN); + lv_obj_set_style_border_width(log_page, 0, LV_PART_MAIN); + lv_obj_set_style_bg_color(log_page, LV_COLOR_MAKE(17,20,16), LV_PART_MAIN); + lv_obj_set_pos(log_page, 0, lv_obj_get_height(usb64_image)); + lv_obj_add_flag(log_page, LV_OBJ_FLAG_HIDDEN); + + ram_label = lv_label_create(scr); + sd_label = lv_label_create(scr); + n64_status_label = lv_label_create(scr); + + lv_label_set_text_fmt(ram_label, "RAM: %uMB", memory_get_ext_ram_size()); + + if (fileio_detected()) { - return; + lv_label_set_text_fmt(sd_label, "SD: Detected"); + lv_obj_set_style_text_color(sd_label, LV_COLOR_MAKE(0,255,0), LV_PART_MAIN); } - - psurface_guilite->fill_rect(0, 0, WIDTH, HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); - - static c_image usb64_image; - memset(&usb64_image, 0, sizeof(c_image)); - BITMAP_INFO _image; - _image.color_bits = 16; - _image.height = 35; - _image.width = 120; - _image.pixel_color_array = usb64_logo; - usb64_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 0, TFT_BG_COLOR); - - //Draw RAM status - snprintf(text_buff, sizeof(text_buff), "Detected RAM: %uMB", memory_get_ext_ram_size()); - extram_size.set_surface(psurface_guilite); - extram_size.set_bg_color(TFT_BG_COLOR); - extram_size.set_font_color(GL_RGB(255, 255, 255)); - extram_size.set_wnd_pos(125, 0, 1, Arial_14_GL.height); - extram_size.set_font_type(&Arial_14_GL); - extram_size.set_str(text_buff); - extram_size.show_window(); - - tft_force_update(); -} - -void tft_try_update() -{ -#if (0) - //Dump the framebuffer to a file on the SD Card, 10 seconds after power up. Assuming 16bit display. - //Convert to png with - //ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb565le -s 320x240 -i tft_dump.bin -f image2 -vcodec png tft_dump.png - if (n64hal_millis() > 10000) + else { - fileio_write_to_file("tft_dump.bin", (uint8_t *)tft_dev_get_fb(), WIDTH * HEIGHT * 2); - debug_print_status("TFT framebuffer dumped\n"); - while (1) yield(); + lv_label_set_text_fmt(sd_label, "SD: Not Detected"); + lv_obj_set_style_text_color(sd_label, LV_COLOR_MAKE(255,0,0), LV_PART_MAIN); } -#endif - if (_tft_update_needed == 0) + lv_label_set_text_fmt(n64_status_label, "N64 is OFF"); + lv_obj_set_style_text_color(n64_status_label, LV_COLOR_MAKE(255,0,0), LV_PART_MAIN); + + lv_obj_update_layout(ram_label); + lv_obj_update_layout(sd_label); + lv_obj_update_layout(n64_status_label); + + lv_obj_align(ram_label, LV_ALIGN_TOP_RIGHT, 0, 0); + lv_obj_align(sd_label, LV_ALIGN_TOP_RIGHT, 0, 10); + lv_obj_align(n64_status_label, LV_ALIGN_TOP_RIGHT, 0, 20); + + lv_obj_t *n64_icon[MAX_CONTROLLERS]; + for (int i = 0; i < MAX_CONTROLLERS; i++) { - return; + lv_coord_t h = lv_obj_get_height(main_page); + n64_icon[i] = lv_canvas_create(main_page); + lv_canvas_set_buffer(n64_icon[i], (void *)controller_icon, 48, 45, LV_IMG_CF_TRUE_COLOR); + lv_obj_align(n64_icon[i], LV_ALIGN_TOP_LEFT, 0, 0 + ((h - 0) * i / 4)); + + controller_status_label[i] = lv_label_create(main_page); + lv_obj_align(controller_status_label[i], LV_ALIGN_TOP_LEFT, 50, 0 + ((h - 0) * i / 4)); + lv_obj_set_style_text_font(controller_status_label[i], &lv_font_montserrat_18, LV_PART_MAIN); + lv_obj_set_style_text_color(controller_status_label[i], LV_COLOR_MAKE(255,255,255), LV_PART_MAIN); + lv_label_set_text(controller_status_label[i], NOT_CONNECTED); + input_dirty[i] = true; } - if (tft_dev_is_busy()) + lv_obj_set_layout(log_page, LV_LAYOUT_FLEX); + lv_obj_set_flex_flow(log_page, LV_FLEX_FLOW_COLUMN); + for (int i = 0; i < _tft_log_max_lines; i++) { - return; + log_lines[i] = lv_label_create(log_page); + lv_obj_set_style_pad_all(log_lines[i], 0, LV_PART_MAIN); + lv_obj_set_style_border_width(log_lines[i], 0, LV_PART_MAIN); + lv_obj_align(log_lines[i], LV_ALIGN_LEFT_MID, 0, 0); + lv_label_set_text(log_lines[i], ""); } - tft_force_update(); + n64_status = false; + + lv_obj_update_layout(scr); + tft_update(); } uint8_t tft_change_page(uint8_t page) { _tft_page = (_tft_page + 1) % _tft_max_pages; - _tft_page_changed = 1; + if (_tft_page == 0) + { + lv_obj_add_flag(log_page, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(main_page, LV_OBJ_FLAG_HIDDEN); + } + else + { + lv_obj_clear_flag(log_page, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(main_page, LV_OBJ_FLAG_HIDDEN); + } return _tft_page; } -void tft_force_update() +void tft_update() { - //These are drawn once when the TFT page has changed. - if (_tft_page_changed) + lv_task_handler(); + if (lv_obj_is_visible(main_page)) { - _tft_page_changed = 0; - if (_tft_page == 0) + for (int i = 0; i < MAX_CONTROLLERS; i++) { - psurface_guilite->fill_rect(0, 40, WIDTH, HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); - static c_image controller_image; - BITMAP_INFO _image; - memset(&controller_image, 0, sizeof(c_image)); - _image.color_bits = 16; - _image.height = 45; - _image.width = 48; - _image.pixel_color_array = controller_icon; - controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((HEIGHT - 45) * 0 / 4), TFT_BG_COLOR); - controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((HEIGHT - 45) * 1 / 4), TFT_BG_COLOR); - controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((HEIGHT - 45) * 2 / 4), TFT_BG_COLOR); - controller_image.draw_image(psurface_guilite, Z_ORDER_LEVEL_0, &_image, 0, 45 + ((HEIGHT - 45) * 3 / 4), TFT_BG_COLOR); + if (input_dirty[i] == false) + { + continue; + } + input_dirty[i] = false; + lv_color_t colour; + if (input_is_connected(i)) + colour = LV_COLOR_MAKE(0, 255, 0); + else + colour = LV_COLOR_MAKE(255, 255, 255); + const char *peri_str = n64_peri_to_string(&n64_in_dev[i]); + lv_obj_set_style_text_color(controller_status_label[i], colour, LV_PART_MAIN); + lv_label_set_text_fmt(controller_status_label[i], "%s\n0x%04x/0x%04x", peri_str, + input_get_id_vendor(i), input_get_id_product(i)); } - else if (_tft_page == 1) - { - psurface_guilite->fill_rect(0, 40, WIDTH, HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); - } - } - //Draw dynamic items here. There are drawn everytime a TFT update is flagged. - if (_tft_page == 0) - { - //Draw controller status and peripheral type - for (int i = 0; i < 4; i++) + if (n64_status != n64hal_input_read(N64_CONSOLE_SENSE_PIN)) { - uint32_t colour = input_is_connected(i) ? GL_RGB(0, 255, 0) : GL_RGB(255, 255, 255); - controller_status[i].set_surface(psurface_guilite); - controller_status[i].set_bg_color(TFT_BG_COLOR); - controller_status[i].set_font_color(colour); - controller_status[i].set_wnd_pos(50, (45 + 0) + ((HEIGHT - 45) * i / 4), WIDTH, Arial_19_GL.height); - controller_status[i].set_font_type(&Arial_19_GL); - controller_status[i].set_str(n64_peri_to_string(&n64_in_dev[i])); - controller_status[i].show_window(); - - snprintf(text_buff, sizeof(text_buff), "0x%04x/0x%04x", input_get_id_vendor(i), input_get_id_product(i)); - controller_id[i].set_surface(psurface_guilite); - controller_id[i].set_font_color(colour); - controller_id[i].set_bg_color(TFT_BG_COLOR); - controller_id[i].set_wnd_pos(50, (45 + 20) + ((HEIGHT - 45) * i / 4), WIDTH, Arial_19_GL.height); - controller_id[i].set_font_type(&Arial_19_GL); - controller_id[i].set_str(text_buff); - controller_id[i].show_window(); + lv_color_t colour; + const char *n64_status_text; + n64_status = n64hal_input_read(N64_CONSOLE_SENSE_PIN); + if (n64_status) + { + n64_status_text = "N64 is ON"; + colour = LV_COLOR_MAKE(0, 255, 0); + } + else + { + n64_status_text = "N64 is OFF"; + colour = LV_COLOR_MAKE(255, 0, 0); + } + lv_obj_set_style_text_color(n64_status_label, colour, LV_PART_MAIN); + lv_label_set_text(n64_status_label, n64_status_text); } } - else if (_tft_page == 1) + else if (lv_obj_is_visible(log_page) && log_dirty) { - psurface_guilite->fill_rect(0, 40, WIDTH, HEIGHT, TFT_BG_COLOR, Z_ORDER_LEVEL_0); + log_dirty = false; for (int i = 0; i < _tft_log_max_lines; i++) { - if (_tft_log_text_lines[i] == NULL) - break; - - tft_log[i].set_surface(psurface_guilite); - tft_log[i].set_bg_color(TFT_BG_COLOR); - tft_log[i].set_font_color(GL_RGB(255, 255, 255)); - tft_log[i].set_wnd_pos(0, 45 + i * Arial_14_GL.height, WIDTH, Arial_14_GL.height); - tft_log[i].set_font_type(&Arial_14_GL); - tft_log[i].set_str(_tft_log_text_lines[i]); - tft_log[i].show_window(); + if (_tft_log_text_lines[i] == NULL) break; + lv_label_set_text(log_lines[i], _tft_log_text_lines[i]); } } +} - //Draw N64 console status - uint32_t colour; - const char *n64_status_text; - if (n64hal_input_read(N64_CONSOLE_SENSE_PIN) == 0) - { - n64_status_text = "N64 is OFF"; - colour = GL_RGB(255, 0, 0); - } - else - { - n64_status_text = "N64 is ON"; - colour = GL_RGB(0, 255, 0); - } - n64_status.set_surface(psurface_guilite); - n64_status.set_bg_color(TFT_BG_COLOR); - n64_status.set_font_color(colour); - n64_status.set_wnd_pos(WIDTH - (10 * 8), 0, 100, Arial_14_GL.height); - n64_status.set_font_type(&Arial_14_GL); - n64_status.set_str(n64_status_text); - n64_status.show_window(); - - //Draw SD Card status - const char *fileio_status_text; - if (fileio_detected() == 0) +void tft_flag_update(uint8_t controller) +{ + if (controller >=0 && controller < sizeof(input_dirty)) { - fileio_status_text = "SD Not Detected"; - colour = GL_RGB(255, 0, 0); + input_dirty[controller] = true; } else { - fileio_status_text = "SD Detected"; - colour = GL_RGB(0, 255, 0); + log_dirty = true; } - n64_status.set_surface(psurface_guilite); - n64_status.set_bg_color(TFT_BG_COLOR); - n64_status.set_font_color(colour); - n64_status.set_wnd_pos(125, Arial_14_GL.height, 100, Arial_14_GL.height); - n64_status.set_font_type(&Arial_14_GL); - n64_status.set_str(fileio_status_text); - n64_status.show_window(); - - //Draw the current games name - n64_status_text = n64_get_current_game(); - n64_status.set_surface(psurface_guilite); - n64_status.set_bg_color(TFT_BG_COLOR); - n64_status.set_font_color(GL_RGB(255, 255, 255)); - n64_status.set_wnd_pos(125, Arial_14_GL.height * 2, 200, Arial_14_GL.height); - n64_status.set_font_type(&Arial_14_GL); - n64_status.set_str(n64_status_text); - n64_status.show_window(); - - tft_dev_draw(true); - - _tft_update_needed = 0; -} - -void tft_flag_update() -{ - _tft_update_needed = 1; } void tft_add_log(char c) @@ -304,7 +276,6 @@ void tft_add_log(char c) tft_log_line_num++; } tft_log_pos = 0; - tft_flag_update(); } else { diff --git a/src/tft.h b/src/tft.h index 63791969..70085647 100644 --- a/src/tft.h +++ b/src/tft.h @@ -4,19 +4,14 @@ #ifndef _TFT_H #define _TFT_H -#define TFT_BG_COLOR GL_RGB(16, 20, 16) - -//TFT API +// TFT API void tft_init(); -uint8_t tft_change_page(uint8_t page); -void tft_force_update(); //Will block until previous DMA complete. -void tft_try_update(); //Will return if DMA busy, or framebuffer hasnt changed -void tft_flag_update(); //Mark the framebuffer as dirty, draw at next update call -void tft_add_log(char c); +uint8_t tft_change_page(uint8_t page); // Change the active TFT page +void tft_update(); // Update the tft display +void tft_flag_update(uint8_t controller); // Mark the framebuffer as dirty, draw at next update call +void tft_add_log(char c); // Add a character to the TFT log screen. Each line should be ended with '\n' -//TFT device specific functions. +// TFT device specific functions. void tft_dev_init(); -void tft_dev_draw(bool force); -bool tft_dev_is_busy(); #endif \ No newline at end of file diff --git a/src/tft/Arial_14.cpp b/src/tft/Arial_14.cpp deleted file mode 100644 index dac9b14d..00000000 --- a/src/tft/Arial_14.cpp +++ /dev/null @@ -1,269 +0,0 @@ -#include "common.h" -#include "GuiLite.h" - -static const unsigned char _32[] PROGMEM = { -0, 42, }; -static const unsigned char _33[] PROGMEM = { -0, 6, 36, 1, 197, 1, 36, 1, 197, 1, 36, 1, 153, 1, 36, 1, 153, 1, 0, 1, 153, 1, 0, 1, 111, 1, 0, 2, 36, 1, 197, 1, 0, 6, }; -static const unsigned char _35[] PROGMEM = { -0, 20, 153, 1, 73, 2, 153, 1, 0, 2, 197, 1, 36, 1, 111, 1, 73, 1, 153, 1, 255, 5, 0, 1, 36, 1, 197, 1, 0, 1, 255, 1, 0, 2, 111, 2, 36, 1, 197, 1, 0, 1, 153, 1, 255, 5, 0, 1, 197, 1, 36, 1, 153, 1, 73, 1, 0, 2, 197, 1, 0, 1, 197, 1, 36, 1, 0, 19, }; -static const unsigned char _37[] PROGMEM = { -0, 31, 111, 1, 255, 2, 0, 2, 36, 1, 255, 1, 0, 3, 255, 1, 0, 1, 111, 2, 0, 1, 153, 1, 73, 1, 0, 3, 255, 1, 0, 1, 111, 2, 73, 1, 197, 1, 0, 4, 111, 1, 255, 2, 0, 1, 197, 1, 36, 1, 0, 7, 73, 1, 153, 1, 73, 1, 255, 2, 36, 1, 0, 4, 197, 1, 36, 1, 197, 1, 36, 1, 73, 1, 153, 1, 0, 3, 111, 2, 0, 1, 197, 1, 36, 1, 73, 1, 153, 1, 0, 3, 255, 1, 0, 2, 73, 1, 255, 2, 36, 1, 0, 30, }; -static const unsigned char _39[] PROGMEM = { -0, 6, 36, 1, 197, 1, 36, 1, 197, 1, 0, 1, 153, 1, 0, 16, }; -static const unsigned char _40[] PROGMEM = { -0, 14, 36, 1, 197, 1, 0, 2, 197, 1, 0, 2, 73, 1, 111, 1, 0, 2, 153, 1, 73, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 153, 1, 73, 1, 0, 2, 73, 1, 111, 1, 0, 3, 197, 1, 0, 3, 36, 1, 197, 1, 0, 4, }; -static const unsigned char _41[] PROGMEM = { -0, 13, 153, 1, 36, 1, 0, 3, 197, 1, 0, 3, 111, 1, 73, 1, 0, 2, 36, 1, 153, 1, 0, 2, 36, 1, 197, 1, 0, 2, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 2, 111, 1, 73, 1, 0, 2, 197, 1, 0, 2, 153, 1, 36, 1, 0, 5, }; -static const unsigned char _43[] PROGMEM = { -0, 33, 197, 1, 0, 5, 197, 1, 0, 3, 255, 5, 0, 3, 197, 1, 0, 5, 197, 1, 0, 26, }; -static const unsigned char _44[] PROGMEM = { -0, 31, 153, 1, 73, 1, 0, 1, 73, 2, 0, 1, 111, 1, 0, 4, }; -static const unsigned char _45[] PROGMEM = { -0, 32, 73, 1, 255, 3, 0, 20, }; -static const unsigned char _46[] PROGMEM = { -0, 31, 153, 1, 73, 1, 0, 9, }; -static const unsigned char _47[] PROGMEM = { -0, 11, 111, 1, 0, 2, 197, 1, 0, 1, 36, 1, 197, 1, 0, 1, 73, 1, 111, 1, 0, 1, 153, 1, 73, 1, 0, 1, 255, 1, 0, 1, 73, 1, 153, 1, 0, 1, 111, 2, 0, 10, }; -static const unsigned char _48[] PROGMEM = { -0, 20, 255, 2, 153, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 153, 1, 111, 1, 0, 1, 197, 1, 73, 1, 0, 2, 255, 2, 153, 1, 0, 19, }; -static const unsigned char _49[] PROGMEM = { -0, 21, 153, 1, 73, 1, 0, 3, 153, 1, 255, 1, 73, 1, 0, 2, 111, 1, 73, 1, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 19, }; -static const unsigned char _50[] PROGMEM = { -0, 19, 111, 1, 255, 3, 0, 1, 36, 1, 255, 1, 0, 2, 111, 1, 153, 1, 0, 4, 36, 1, 197, 1, 0, 4, 153, 1, 73, 1, 0, 3, 153, 1, 111, 1, 0, 3, 197, 1, 111, 1, 0, 3, 197, 1, 73, 1, 0, 3, 73, 1, 255, 4, 197, 1, 0, 18, }; -static const unsigned char _51[] PROGMEM = { -0, 19, 73, 1, 255, 2, 153, 1, 0, 2, 255, 1, 0, 2, 153, 1, 73, 1, 0, 4, 153, 1, 73, 1, 0, 2, 36, 1, 255, 1, 153, 1, 0, 5, 73, 1, 153, 1, 0, 4, 36, 1, 197, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 73, 1, 255, 2, 197, 1, 0, 19, }; -static const unsigned char _52[] PROGMEM = { -0, 21, 36, 1, 197, 1, 0, 4, 197, 2, 0, 3, 111, 1, 153, 1, 197, 1, 0, 2, 36, 1, 197, 1, 36, 1, 197, 1, 0, 2, 197, 1, 36, 2, 197, 1, 0, 1, 36, 1, 255, 4, 197, 1, 0, 3, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 19, }; -static const unsigned char _53[] PROGMEM = { -0, 19, 73, 1, 255, 3, 73, 1, 0, 1, 111, 2, 0, 4, 197, 1, 73, 1, 0, 4, 255, 1, 197, 1, 255, 2, 0, 3, 36, 1, 0, 1, 36, 1, 153, 1, 0, 4, 36, 1, 197, 1, 0, 1, 255, 1, 0, 2, 36, 1, 153, 1, 0, 1, 73, 1, 255, 2, 197, 1, 0, 19, }; -static const unsigned char _54[] PROGMEM = { -0, 19, 36, 1, 255, 3, 0, 2, 197, 1, 36, 1, 0, 1, 111, 1, 153, 1, 36, 1, 197, 1, 0, 4, 73, 1, 153, 1, 197, 1, 255, 2, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 153, 1, 73, 1, 153, 1, 0, 2, 36, 1, 197, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 36, 1, 255, 2, 197, 1, 0, 19, }; -static const unsigned char _55[] PROGMEM = { -0, 18, 36, 1, 255, 4, 197, 1, 0, 4, 197, 1, 73, 1, 0, 3, 73, 1, 153, 1, 0, 4, 197, 1, 36, 1, 0, 3, 73, 1, 197, 1, 0, 4, 153, 1, 73, 1, 0, 4, 197, 1, 36, 1, 0, 4, 255, 1, 0, 21, }; -static const unsigned char _56[] PROGMEM = { -0, 19, 36, 1, 255, 3, 0, 2, 197, 1, 36, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 2, 197, 1, 255, 1, 111, 1, 0, 2, 255, 1, 36, 1, 0, 1, 111, 1, 153, 1, 36, 1, 197, 1, 0, 3, 255, 1, 0, 1, 255, 1, 36, 1, 0, 1, 73, 1, 197, 1, 0, 1, 73, 1, 255, 3, 0, 19, }; -static const unsigned char _57[] PROGMEM = { -0, 19, 73, 1, 255, 2, 153, 1, 0, 2, 255, 1, 36, 1, 0, 1, 111, 2, 36, 1, 197, 1, 0, 2, 36, 1, 197, 1, 0, 1, 255, 1, 36, 1, 0, 1, 111, 1, 197, 1, 0, 1, 73, 1, 255, 2, 153, 1, 197, 1, 0, 4, 73, 1, 153, 1, 0, 1, 255, 1, 0, 2, 197, 1, 73, 1, 0, 1, 73, 1, 255, 2, 153, 1, 0, 19, }; -static const unsigned char _58[] PROGMEM = { -0, 16, 153, 1, 73, 1, 0, 13, 153, 1, 73, 1, 0, 9, }; -static const unsigned char _59[] PROGMEM = { -0, 16, 153, 1, 73, 1, 0, 13, 153, 1, 73, 1, 0, 1, 73, 2, 0, 1, 111, 1, 0, 4, }; -static const unsigned char _60[] PROGMEM = { -0, 34, 111, 1, 153, 1, 0, 2, 197, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 5, 197, 1, 255, 1, 111, 1, 0, 5, 111, 1, 153, 1, 0, 24, }; -static const unsigned char _61[] PROGMEM = { -0, 37, 255, 4, 153, 1, 0, 7, 255, 4, 153, 1, 0, 30, }; -static const unsigned char _62[] PROGMEM = { -0, 31, 255, 1, 36, 1, 0, 5, 197, 1, 255, 1, 153, 1, 0, 5, 73, 1, 197, 1, 0, 2, 197, 1, 255, 1, 153, 1, 0, 2, 255, 1, 36, 1, 0, 27, }; -static const unsigned char _63[] PROGMEM = { -0, 19, 73, 1, 255, 3, 0, 2, 255, 1, 0, 2, 73, 1, 197, 1, 0, 4, 73, 1, 197, 1, 0, 3, 73, 1, 255, 1, 0, 3, 36, 1, 255, 1, 0, 4, 73, 1, 153, 1, 0, 10, 73, 1, 153, 1, 0, 20, }; -static const unsigned char _64[] PROGMEM = { -0, 36, 36, 1, 255, 4, 111, 1, 0, 4, 153, 1, 255, 1, 0, 4, 197, 1, 153, 1, 0, 2, 73, 1, 197, 1, 0, 1, 153, 1, 255, 1, 197, 1, 153, 1, 73, 1, 197, 1, 73, 1, 0, 1, 197, 1, 73, 1, 111, 1, 153, 1, 0, 1, 73, 1, 255, 1, 0, 1, 73, 1, 153, 1, 0, 1, 255, 1, 0, 1, 255, 1, 36, 1, 0, 1, 36, 1, 197, 1, 0, 1, 73, 1, 153, 1, 0, 1, 255, 1, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 1, 153, 1, 111, 1, 0, 1, 255, 1, 36, 1, 255, 1, 36, 1, 0, 1, 255, 1, 111, 1, 73, 1, 255, 1, 0, 2, 153, 2, 73, 1, 255, 2, 111, 1, 255, 2, 0, 4, 197, 2, 0, 5, 197, 2, 0, 3, 111, 1, 255, 5, 36, 1, 0, 12, }; -static const unsigned char _65[] PROGMEM = { -0, 27, 73, 1, 197, 1, 0, 6, 197, 1, 111, 1, 73, 1, 0, 4, 73, 1, 153, 1, 36, 1, 153, 1, 0, 4, 153, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 2, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 2, 153, 1, 255, 5, 36, 1, 0, 1, 255, 1, 0, 4, 111, 3, 73, 1, 0, 5, 255, 1, 0, 24, }; -static const unsigned char _66[] PROGMEM = { -0, 22, 197, 1, 255, 3, 153, 1, 0, 2, 197, 1, 36, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 153, 1, 36, 1, 0, 1, 197, 1, 255, 4, 0, 2, 197, 1, 36, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 2, 153, 1, 73, 1, 0, 1, 197, 1, 255, 3, 153, 1, 0, 22, }; -static const unsigned char _67[] PROGMEM = { -0, 23, 111, 1, 255, 2, 153, 1, 0, 2, 111, 1, 197, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 36, 2, 0, 1, 255, 1, 0, 6, 255, 1, 0, 6, 197, 1, 36, 1, 0, 5, 111, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 255, 2, 197, 1, 0, 22, }; -static const unsigned char _68[] PROGMEM = { -0, 22, 255, 4, 111, 1, 0, 2, 255, 1, 0, 3, 197, 1, 73, 1, 0, 1, 255, 1, 0, 3, 73, 1, 153, 1, 0, 1, 255, 1, 0, 3, 36, 1, 197, 1, 0, 1, 255, 1, 0, 3, 36, 1, 197, 1, 0, 1, 255, 1, 0, 3, 73, 1, 153, 1, 0, 1, 255, 1, 0, 3, 197, 1, 73, 1, 0, 1, 255, 4, 111, 1, 0, 22, }; -static const unsigned char _69[] PROGMEM = { -0, 19, 255, 4, 111, 1, 0, 1, 255, 1, 0, 5, 255, 1, 0, 5, 255, 4, 36, 1, 0, 1, 255, 1, 0, 5, 255, 1, 0, 5, 255, 1, 0, 5, 255, 4, 153, 1, 0, 18, }; -static const unsigned char _70[] PROGMEM = { -0, 19, 197, 1, 255, 3, 197, 1, 0, 1, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 255, 3, 36, 1, 0, 1, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 21, }; -static const unsigned char _71[] PROGMEM = { -0, 26, 111, 1, 255, 3, 111, 1, 0, 2, 111, 1, 197, 1, 0, 3, 255, 1, 73, 1, 0, 1, 255, 1, 36, 1, 0, 3, 73, 1, 111, 1, 36, 1, 197, 1, 0, 6, 36, 1, 197, 1, 0, 2, 73, 1, 255, 2, 153, 1, 0, 1, 255, 1, 36, 1, 0, 3, 73, 1, 153, 1, 0, 1, 111, 1, 197, 1, 0, 3, 153, 2, 0, 2, 73, 1, 255, 3, 153, 1, 0, 25, }; -static const unsigned char _72[] PROGMEM = { -0, 22, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 255, 4, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 21, }; -static const unsigned char _73[] PROGMEM = { -0, 7, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 6, }; -static const unsigned char _74[] PROGMEM = { -0, 18, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 255, 2, 153, 1, 0, 16, }; -static const unsigned char _75[] PROGMEM = { -0, 22, 197, 1, 36, 1, 0, 2, 153, 1, 255, 1, 0, 1, 197, 1, 36, 1, 0, 1, 153, 2, 0, 2, 197, 1, 36, 1, 153, 2, 0, 3, 197, 2, 255, 1, 36, 1, 0, 3, 197, 1, 111, 2, 197, 1, 0, 3, 197, 1, 36, 1, 0, 1, 197, 1, 153, 1, 0, 2, 197, 1, 36, 1, 0, 2, 255, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 2, 73, 1, 255, 1, 0, 21, }; -static const unsigned char _76[] PROGMEM = { -0, 19, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 255, 4, 0, 18, }; -static const unsigned char _77[] PROGMEM = { -0, 25, 197, 1, 153, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 2, 0, 2, 111, 1, 197, 1, 73, 1, 0, 1, 197, 1, 111, 1, 36, 1, 0, 1, 153, 1, 111, 1, 73, 1, 0, 1, 197, 1, 73, 1, 111, 1, 0, 1, 197, 1, 111, 1, 73, 1, 0, 1, 197, 1, 36, 1, 153, 1, 36, 1, 111, 2, 73, 1, 0, 1, 197, 1, 36, 1, 153, 1, 111, 1, 73, 1, 111, 1, 73, 1, 0, 1, 197, 1, 36, 1, 111, 1, 197, 1, 0, 1, 111, 1, 73, 1, 0, 1, 197, 1, 36, 2, 197, 1, 0, 1, 111, 1, 73, 1, 0, 24, }; -static const unsigned char _78[] PROGMEM = { -0, 22, 197, 1, 111, 1, 0, 2, 111, 2, 0, 1, 197, 1, 255, 1, 0, 2, 111, 2, 0, 1, 197, 1, 111, 2, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 197, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 73, 1, 111, 3, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 111, 1, 0, 21, }; -static const unsigned char _79[] PROGMEM = { -0, 26, 111, 1, 255, 3, 0, 3, 111, 1, 197, 1, 0, 2, 73, 1, 255, 1, 0, 2, 197, 1, 36, 1, 0, 3, 153, 1, 73, 1, 0, 1, 255, 1, 0, 4, 111, 2, 0, 1, 255, 1, 0, 4, 111, 2, 0, 1, 197, 1, 36, 1, 0, 3, 153, 1, 73, 1, 0, 1, 111, 1, 197, 1, 0, 2, 73, 1, 255, 1, 0, 3, 111, 1, 255, 3, 0, 26, }; -static const unsigned char _80[] PROGMEM = { -0, 19, 197, 1, 255, 3, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 255, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 0, 1, 197, 1, 36, 1, 0, 2, 255, 1, 0, 1, 197, 1, 255, 3, 111, 1, 0, 1, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 21, }; -static const unsigned char _81[] PROGMEM = { -0, 26, 73, 1, 255, 3, 0, 3, 73, 1, 255, 1, 0, 2, 73, 1, 255, 1, 0, 2, 153, 1, 73, 1, 0, 3, 153, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 3, 111, 2, 0, 1, 197, 1, 36, 1, 0, 3, 111, 2, 0, 1, 153, 1, 73, 1, 0, 1, 73, 1, 0, 1, 153, 1, 73, 1, 0, 1, 73, 1, 255, 1, 0, 1, 73, 1, 255, 1, 197, 1, 0, 3, 73, 1, 255, 2, 153, 1, 197, 2, 0, 24, }; -static const unsigned char _82[] PROGMEM = { -0, 22, 197, 1, 255, 4, 0, 2, 197, 1, 36, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 2, 153, 1, 111, 1, 0, 1, 197, 1, 255, 3, 197, 1, 0, 2, 197, 1, 36, 1, 0, 1, 153, 1, 111, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 2, 73, 1, 255, 1, 0, 21, }; -static const unsigned char _83[] PROGMEM = { -0, 23, 255, 3, 153, 1, 0, 2, 197, 1, 73, 1, 0, 2, 197, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 5, 73, 1, 255, 2, 73, 1, 0, 6, 153, 1, 255, 1, 73, 1, 0, 5, 36, 1, 197, 1, 0, 1, 255, 1, 73, 1, 0, 2, 111, 1, 153, 1, 0, 1, 36, 1, 255, 3, 197, 1, 0, 22, }; -static const unsigned char _84[] PROGMEM = { -0, 18, 197, 1, 255, 5, 0, 2, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 4, 36, 1, 197, 1, 0, 20, }; -static const unsigned char _85[] PROGMEM = { -0, 22, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 1, 153, 1, 111, 1, 0, 1, 36, 1, 255, 1, 0, 3, 255, 3, 36, 1, 0, 22, }; -static const unsigned char _86[] PROGMEM = { -0, 24, 111, 1, 197, 1, 0, 4, 36, 1, 255, 1, 0, 1, 255, 1, 36, 1, 0, 3, 111, 1, 153, 1, 0, 1, 111, 2, 0, 3, 197, 1, 36, 1, 0, 1, 36, 1, 255, 1, 0, 2, 73, 1, 197, 1, 0, 3, 153, 1, 73, 1, 0, 1, 153, 1, 73, 1, 0, 3, 73, 1, 153, 1, 36, 1, 255, 1, 0, 5, 197, 1, 153, 1, 111, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 26, }; -static const unsigned char _87[] PROGMEM = { -0, 30, 73, 1, 153, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 197, 1, 36, 1, 197, 1, 0, 2, 153, 1, 111, 1, 73, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 0, 2, 153, 1, 36, 1, 153, 1, 0, 1, 73, 1, 111, 1, 0, 1, 153, 1, 73, 1, 36, 1, 153, 1, 0, 1, 197, 1, 0, 1, 153, 1, 73, 1, 0, 1, 73, 1, 111, 2, 73, 1, 0, 1, 153, 1, 36, 1, 197, 1, 0, 2, 36, 1, 153, 2, 36, 1, 0, 1, 111, 1, 73, 1, 197, 1, 0, 3, 153, 1, 197, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 3, 153, 2, 0, 3, 255, 1, 73, 1, 0, 31, }; -static const unsigned char _88[] PROGMEM = { -0, 21, 36, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 0, 1, 73, 1, 197, 1, 0, 2, 255, 1, 0, 3, 153, 1, 73, 1, 111, 1, 73, 1, 0, 4, 255, 1, 153, 1, 0, 4, 36, 1, 153, 1, 255, 1, 0, 4, 197, 1, 36, 1, 111, 1, 153, 1, 0, 2, 111, 2, 0, 2, 197, 1, 73, 1, 111, 1, 197, 1, 0, 3, 36, 1, 255, 1, 0, 21, }; -static const unsigned char _89[] PROGMEM = { -0, 24, 111, 1, 153, 1, 0, 4, 73, 1, 197, 1, 0, 1, 111, 2, 0, 3, 255, 1, 0, 3, 197, 1, 36, 1, 0, 1, 153, 1, 36, 1, 0, 3, 36, 1, 197, 1, 73, 1, 111, 1, 0, 5, 73, 1, 197, 1, 0, 6, 73, 1, 153, 1, 0, 6, 73, 1, 153, 1, 0, 6, 73, 1, 153, 1, 0, 27, }; -static const unsigned char _90[] PROGMEM = { -0, 22, 255, 6, 0, 5, 197, 1, 111, 1, 0, 4, 153, 2, 0, 4, 111, 1, 197, 1, 0, 4, 73, 1, 255, 1, 0, 4, 36, 1, 255, 1, 36, 1, 0, 4, 255, 1, 73, 1, 0, 4, 111, 1, 255, 6, 0, 21, }; -static const unsigned char _91[] PROGMEM = { -0, 10, 255, 2, 0, 1, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 1, 0, 2, 255, 2, 0, 3, }; -static const unsigned char _93[] PROGMEM = { -0, 9, 111, 1, 255, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 0, 1, 73, 1, 153, 1, 111, 1, 255, 1, 153, 1, 0, 3, }; -static const unsigned char _95[] PROGMEM = { -0, 72, 197, 1, 255, 5, 0, 6, }; -static const unsigned char _97[] PROGMEM = { -0, 31, 36, 1, 255, 3, 0, 2, 197, 1, 36, 1, 0, 1, 153, 1, 73, 1, 0, 2, 197, 1, 255, 2, 111, 1, 0, 1, 255, 1, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 255, 1, 0, 2, 255, 1, 111, 1, 0, 1, 153, 1, 255, 2, 153, 2, 0, 18, }; -static const unsigned char _98[] PROGMEM = { -0, 19, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 153, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 73, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 73, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 153, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 153, 1, 255, 2, 0, 19, }; -static const unsigned char _99[] PROGMEM = { -0, 32, 197, 1, 255, 2, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 36, 1, 255, 1, 0, 1, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 153, 1, 111, 1, 0, 2, 255, 1, 0, 2, 197, 1, 255, 2, 73, 1, 0, 18, }; -static const unsigned char _100[] PROGMEM = { -0, 22, 111, 1, 153, 1, 0, 4, 111, 1, 153, 1, 0, 1, 36, 1, 255, 2, 153, 2, 0, 1, 197, 1, 73, 1, 0, 1, 197, 1, 153, 1, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 73, 1, 0, 1, 153, 2, 0, 1, 36, 1, 255, 2, 197, 1, 153, 1, 0, 18, }; -static const unsigned char _101[] PROGMEM = { -0, 32, 255, 3, 0, 2, 197, 1, 36, 1, 0, 1, 73, 1, 153, 1, 0, 1, 255, 4, 197, 1, 0, 1, 255, 1, 0, 5, 197, 1, 111, 1, 0, 1, 111, 1, 153, 1, 0, 2, 255, 3, 0, 19, }; -static const unsigned char _102[] PROGMEM = { -0, 14, 111, 1, 255, 1, 0, 2, 197, 1, 36, 1, 0, 1, 153, 1, 255, 2, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 12, }; -static const unsigned char _103[] PROGMEM = { -0, 32, 255, 2, 111, 1, 153, 1, 0, 1, 153, 1, 111, 1, 0, 1, 153, 2, 0, 1, 197, 1, 36, 1, 0, 1, 73, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 73, 1, 153, 1, 0, 1, 153, 1, 111, 1, 0, 1, 153, 2, 0, 2, 255, 2, 153, 2, 0, 4, 111, 2, 0, 1, 153, 1, 255, 2, 197, 1, 0, 7, }; -static const unsigned char _104[] PROGMEM = { -0, 19, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 4, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 111, 1, 0, 1, 153, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 18, }; -static const unsigned char _105[] PROGMEM = { -0, 7, 197, 1, 0, 3, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 6, }; -static const unsigned char _106[] PROGMEM = { -0, 7, 197, 1, 0, 3, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 255, 2, 0, 2, }; -static const unsigned char _107[] PROGMEM = { -0, 16, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 3, 197, 1, 36, 2, 255, 1, 0, 1, 197, 1, 36, 1, 197, 1, 0, 2, 197, 1, 255, 1, 73, 1, 0, 2, 197, 1, 73, 1, 197, 1, 0, 2, 197, 1, 36, 1, 153, 1, 111, 1, 0, 1, 197, 1, 36, 1, 0, 1, 255, 1, 0, 15, }; -static const unsigned char _108[] PROGMEM = { -0, 7, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 1, 197, 1, 0, 6, }; -static const unsigned char _109[] PROGMEM = { -0, 41, 197, 1, 153, 1, 255, 1, 197, 1, 111, 1, 255, 1, 197, 1, 0, 1, 197, 1, 111, 1, 0, 1, 197, 1, 111, 1, 0, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 0, 24, }; -static const unsigned char _110[] PROGMEM = { -0, 31, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 73, 1, 0, 1, 153, 1, 73, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 18, }; -static const unsigned char _111[] PROGMEM = { -0, 31, 36, 1, 255, 2, 197, 1, 0, 2, 197, 1, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 255, 1, 0, 2, 73, 1, 153, 1, 0, 1, 197, 1, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 36, 1, 255, 2, 153, 1, 0, 19, }; -static const unsigned char _112[] PROGMEM = { -0, 31, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 111, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 111, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 153, 1, 255, 2, 0, 2, 197, 1, 36, 1, 0, 4, 197, 1, 36, 1, 0, 9, }; -static const unsigned char _113[] PROGMEM = { -0, 31, 73, 1, 255, 2, 111, 1, 153, 1, 0, 1, 255, 1, 36, 1, 0, 1, 197, 1, 153, 1, 73, 1, 153, 1, 0, 2, 73, 1, 153, 1, 73, 1, 153, 1, 0, 2, 73, 1, 153, 1, 0, 1, 255, 1, 36, 1, 0, 1, 153, 2, 0, 1, 73, 1, 255, 2, 153, 2, 0, 4, 73, 1, 153, 1, 0, 4, 73, 1, 153, 1, 0, 6, }; -static const unsigned char _114[] PROGMEM = { -0, 21, 197, 1, 153, 1, 255, 1, 0, 1, 197, 1, 111, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 2, 197, 1, 36, 1, 0, 13, }; -static const unsigned char _115[] PROGMEM = { -0, 31, 111, 1, 255, 2, 197, 1, 0, 2, 255, 1, 0, 2, 153, 1, 73, 1, 0, 1, 197, 1, 255, 2, 0, 5, 197, 1, 255, 1, 153, 1, 36, 1, 255, 1, 0, 2, 73, 1, 197, 1, 0, 1, 73, 1, 255, 3, 36, 1, 0, 18, }; -static const unsigned char _116[] PROGMEM = { -0, 10, 153, 1, 36, 1, 0, 1, 197, 1, 36, 1, 111, 1, 255, 2, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 153, 1, 255, 1, 0, 9, }; -static const unsigned char _117[] PROGMEM = { -0, 31, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 197, 1, 36, 1, 0, 1, 153, 1, 111, 1, 0, 1, 197, 1, 73, 1, 0, 1, 197, 1, 111, 1, 0, 1, 73, 1, 255, 2, 153, 1, 111, 1, 0, 18, }; -static const unsigned char _118[] PROGMEM = { -0, 30, 36, 1, 197, 1, 0, 2, 36, 1, 197, 1, 0, 1, 197, 1, 36, 1, 0, 1, 111, 2, 0, 1, 73, 1, 111, 1, 0, 1, 197, 1, 0, 3, 255, 1, 73, 1, 153, 1, 0, 3, 153, 2, 73, 1, 0, 3, 73, 1, 255, 1, 0, 20, }; -static const unsigned char _119[] PROGMEM = { -0, 51, 197, 1, 36, 1, 0, 1, 73, 1, 255, 1, 0, 2, 111, 2, 0, 1, 111, 2, 0, 1, 153, 1, 197, 1, 36, 1, 0, 1, 197, 1, 36, 1, 0, 1, 36, 1, 197, 1, 0, 1, 197, 1, 73, 1, 111, 1, 36, 1, 197, 1, 0, 3, 197, 1, 73, 1, 153, 1, 0, 1, 197, 1, 111, 2, 0, 3, 111, 1, 197, 1, 73, 1, 0, 1, 197, 1, 153, 1, 36, 1, 0, 3, 36, 1, 255, 1, 36, 1, 0, 1, 111, 1, 197, 1, 0, 32, }; -static const unsigned char _120[] PROGMEM = { -0, 30, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 197, 1, 0, 1, 73, 1, 197, 1, 73, 1, 255, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 197, 1, 255, 1, 111, 1, 0, 2, 111, 1, 153, 1, 0, 1, 255, 1, 36, 1, 111, 1, 255, 1, 0, 2, 73, 1, 255, 1, 0, 18, }; -static const unsigned char _121[] PROGMEM = { -0, 30, 73, 1, 197, 1, 0, 3, 255, 1, 0, 1, 197, 1, 73, 1, 0, 1, 111, 1, 153, 1, 0, 1, 111, 1, 153, 1, 0, 1, 197, 1, 36, 1, 0, 2, 255, 1, 36, 1, 197, 1, 0, 3, 153, 1, 197, 1, 73, 1, 0, 3, 36, 1, 255, 1, 0, 4, 111, 2, 0, 3, 255, 2, 0, 9, }; -static const unsigned char _122[] PROGMEM = { -0, 31, 153, 1, 255, 3, 197, 1, 0, 4, 153, 1, 36, 1, 0, 3, 153, 1, 73, 1, 0, 3, 111, 2, 0, 3, 73, 1, 153, 1, 0, 4, 255, 4, 197, 1, 0, 18, }; -static const unsigned char _14849714[] PROGMEM = { -0, 38, 36, 1, 0, 10, 197, 1, 73, 1, 0, 8, 73, 1, 255, 1, 197, 1, 0, 8, 197, 1, 255, 2, 73, 1, 0, 6, 73, 1, 255, 3, 197, 1, 0, 6, 197, 1, 255, 4, 73, 1, 0, 4, 73, 1, 255, 5, 197, 1, 0, 4, 197, 1, 255, 6, 111, 1, 0, 34, }; -static const unsigned char _14849724[] PROGMEM = { -0, 46, 197, 1, 255, 6, 111, 1, 0, 4, 255, 5, 153, 1, 0, 5, 111, 1, 255, 4, 36, 1, 0, 6, 255, 3, 153, 1, 0, 7, 111, 1, 255, 2, 36, 1, 0, 8, 255, 1, 153, 1, 0, 9, 111, 1, 36, 1, 0, 37, }; -static LATTICE lattice_array[] = { - {32, 3, _32}, - {33, 2, _33}, - {35, 6, _35}, - {37, 10, _37}, - {39, 2, _39}, - {40, 4, _40}, - {41, 4, _41}, - {43, 6, _43}, - {44, 3, _44}, - {45, 4, _45}, - {46, 3, _46}, - {47, 3, _47}, - {48, 6, _48}, - {49, 6, _49}, - {50, 6, _50}, - {51, 6, _51}, - {52, 6, _52}, - {53, 6, _53}, - {54, 6, _54}, - {55, 6, _55}, - {56, 6, _56}, - {57, 6, _57}, - {58, 3, _58}, - {59, 3, _59}, - {60, 6, _60}, - {61, 6, _61}, - {62, 6, _62}, - {63, 6, _63}, - {64, 11, _64}, - {65, 8, _65}, - {66, 7, _66}, - {67, 7, _67}, - {68, 7, _68}, - {69, 6, _69}, - {70, 6, _70}, - {71, 8, _71}, - {72, 7, _72}, - {73, 2, _73}, - {74, 5, _74}, - {75, 7, _75}, - {76, 6, _76}, - {77, 8, _77}, - {78, 7, _78}, - {79, 8, _79}, - {80, 6, _80}, - {81, 8, _81}, - {82, 7, _82}, - {83, 7, _83}, - {84, 6, _84}, - {85, 7, _85}, - {86, 8, _86}, - {87, 10, _87}, - {88, 7, _88}, - {89, 8, _89}, - {90, 7, _90}, - {91, 3, _91}, - {93, 3, _93}, - {95, 6, _95}, - {97, 6, _97}, - {98, 6, _98}, - {99, 6, _99}, - {100, 6, _100}, - {101, 6, _101}, - {102, 4, _102}, - {103, 6, _103}, - {104, 6, _104}, - {105, 2, _105}, - {106, 2, _106}, - {107, 5, _107}, - {108, 2, _108}, - {109, 8, _109}, - {110, 6, _110}, - {111, 6, _111}, - {112, 6, _112}, - {113, 6, _113}, - {114, 4, _114}, - {115, 6, _115}, - {116, 3, _116}, - {117, 6, _117}, - {118, 6, _118}, - {119, 10, _119}, - {120, 6, _120}, - {121, 6, _121}, - {122, 6, _122}, - {14849714, 11, _14849714}, - {14849724, 11, _14849724}, -}; -extern const LATTICE_FONT_INFO Arial_14_GL; -const LATTICE_FONT_INFO Arial_14_GL ={ - 14, - 86, - lattice_array -}; diff --git a/src/tft/Arial_19.cpp b/src/tft/Arial_19.cpp deleted file mode 100644 index df26c029..00000000 --- a/src/tft/Arial_19.cpp +++ /dev/null @@ -1,269 +0,0 @@ -#include "common.h" -#include "GuiLite.h" - -static const unsigned char _32[] PROGMEM = { -0, 95, }; -static const unsigned char _33[] PROGMEM = { -0, 17, 255, 1, 197, 1, 0, 3, 255, 1, 197, 1, 0, 3, 255, 1, 197, 1, 0, 3, 255, 1, 197, 1, 0, 3, 255, 1, 197, 1, 0, 3, 197, 1, 153, 1, 0, 3, 197, 1, 153, 1, 0, 3, 153, 1, 111, 1, 0, 3, 153, 1, 111, 1, 0, 3, 153, 1, 111, 1, 0, 8, 255, 1, 197, 1, 0, 21, }; -static const unsigned char _35[] PROGMEM = { -0, 30, 111, 2, 0, 2, 153, 1, 73, 1, 0, 3, 153, 1, 73, 1, 0, 2, 197, 1, 36, 1, 0, 3, 255, 1, 0, 2, 36, 1, 197, 1, 0, 3, 36, 1, 197, 1, 0, 2, 73, 1, 153, 1, 0, 1, 153, 1, 255, 8, 0, 2, 153, 1, 73, 1, 0, 2, 153, 1, 73, 1, 0, 3, 197, 1, 36, 1, 0, 2, 255, 1, 0, 4, 255, 1, 0, 2, 36, 1, 197, 1, 0, 2, 153, 1, 255, 8, 0, 1, 111, 2, 0, 2, 153, 1, 73, 1, 0, 3, 153, 1, 73, 1, 0, 2, 197, 1, 36, 1, 0, 3, 197, 1, 36, 1, 0, 2, 255, 1, 0, 39, }; -static const unsigned char _37[] PROGMEM = { -0, 47, 153, 1, 255, 2, 73, 1, 0, 4, 197, 1, 73, 1, 0, 4, 73, 1, 255, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 2, 73, 1, 153, 1, 0, 5, 153, 1, 197, 1, 0, 2, 197, 1, 111, 1, 0, 2, 197, 1, 36, 1, 0, 5, 153, 2, 0, 2, 197, 1, 153, 1, 0, 1, 111, 2, 0, 6, 153, 2, 0, 2, 197, 1, 111, 1, 0, 1, 255, 1, 0, 7, 73, 1, 255, 1, 0, 1, 36, 1, 255, 1, 36, 1, 111, 2, 0, 1, 255, 3, 36, 1, 0, 3, 153, 1, 255, 2, 73, 1, 0, 1, 255, 1, 0, 1, 153, 1, 197, 1, 0, 1, 111, 1, 255, 1, 0, 7, 153, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 5, 36, 1, 197, 1, 0, 2, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 5, 153, 1, 73, 1, 0, 2, 255, 1, 111, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 4, 73, 1, 153, 1, 0, 3, 153, 1, 197, 1, 0, 1, 111, 1, 197, 1, 0, 5, 197, 1, 36, 1, 0, 4, 197, 1, 255, 2, 36, 1, 0, 61, }; -static const unsigned char _39[] PROGMEM = { -0, 10, 255, 1, 153, 1, 0, 1, 255, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 1, 197, 1, 73, 1, 0, 36, }; -static const unsigned char _40[] PROGMEM = { -0, 22, 153, 2, 0, 3, 111, 1, 197, 1, 0, 4, 255, 1, 36, 1, 0, 3, 153, 1, 197, 1, 0, 4, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 111, 1, 255, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 4, 255, 1, 111, 1, 0, 4, 153, 1, 197, 1, 0, 5, 255, 1, 73, 1, 0, 4, 111, 1, 197, 1, 0, 5, 153, 2, 0, 6, }; -static const unsigned char _41[] PROGMEM = { -0, 19, 111, 1, 197, 1, 0, 5, 153, 2, 0, 4, 36, 1, 255, 1, 36, 1, 0, 4, 153, 1, 197, 1, 0, 4, 73, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 4, 255, 1, 153, 1, 0, 4, 197, 1, 153, 1, 0, 4, 255, 1, 153, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 153, 2, 0, 3, 36, 1, 255, 1, 36, 1, 0, 3, 153, 2, 0, 3, 111, 1, 197, 1, 0, 9, }; -static const unsigned char _43[] PROGMEM = { -0, 54, 73, 1, 255, 1, 36, 1, 0, 7, 73, 1, 255, 1, 36, 1, 0, 7, 73, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 7, 111, 1, 0, 4, 73, 1, 255, 1, 36, 1, 0, 7, 73, 1, 255, 1, 36, 1, 0, 7, 73, 1, 255, 1, 36, 1, 0, 73, }; -static const unsigned char _44[] PROGMEM = { -0, 72, 255, 1, 153, 1, 0, 3, 36, 1, 153, 1, 0, 3, 111, 2, 0, 3, 197, 1, 0, 7, }; -static const unsigned char _45[] PROGMEM = { -0, 60, 36, 1, 255, 4, 197, 1, 0, 48, }; -static const unsigned char _46[] PROGMEM = { -0, 72, 255, 1, 153, 1, 0, 21, }; -static const unsigned char _47[] PROGMEM = { -0, 19, 255, 1, 0, 3, 73, 1, 153, 1, 0, 3, 153, 1, 73, 1, 0, 3, 255, 1, 0, 3, 73, 1, 153, 1, 0, 3, 153, 1, 111, 1, 0, 3, 197, 1, 36, 1, 0, 2, 36, 1, 197, 1, 0, 3, 111, 2, 0, 3, 197, 1, 36, 1, 0, 2, 36, 1, 197, 1, 0, 3, 111, 2, 0, 23, }; -static const unsigned char _48[] PROGMEM = { -0, 30, 255, 4, 0, 4, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 0, 4, 255, 1, 111, 1, 0, 1, 197, 2, 0, 4, 197, 2, 0, 1, 197, 1, 153, 1, 0, 4, 153, 1, 197, 1, 0, 1, 255, 1, 153, 1, 0, 4, 153, 1, 255, 1, 0, 1, 255, 1, 153, 1, 0, 4, 153, 1, 255, 1, 0, 1, 197, 1, 153, 1, 0, 4, 153, 1, 197, 1, 0, 1, 197, 2, 0, 4, 197, 1, 153, 1, 0, 1, 111, 1, 255, 1, 0, 4, 255, 1, 111, 1, 0, 2, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 4, 255, 4, 0, 38, }; -static const unsigned char _49[] PROGMEM = { -0, 32, 197, 1, 73, 1, 0, 6, 153, 1, 255, 1, 73, 1, 0, 5, 255, 3, 73, 1, 0, 4, 197, 2, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 38, }; -static const unsigned char _50[] PROGMEM = { -0, 29, 36, 1, 255, 4, 0, 3, 36, 1, 255, 1, 197, 1, 0, 2, 255, 2, 0, 2, 153, 1, 255, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 6, 73, 1, 255, 1, 73, 1, 0, 5, 36, 1, 255, 1, 197, 1, 0, 6, 255, 2, 0, 5, 36, 1, 255, 1, 197, 1, 0, 5, 73, 1, 255, 1, 197, 1, 0, 5, 36, 1, 255, 1, 153, 1, 0, 6, 197, 2, 0, 6, 36, 1, 255, 7, 111, 1, 0, 36, }; -static const unsigned char _51[] PROGMEM = { -0, 29, 73, 1, 255, 3, 111, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 2, 255, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 0, 7, 111, 1, 255, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 5, 255, 2, 197, 1, 0, 8, 153, 1, 255, 1, 36, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 7, 255, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 111, 1, 255, 1, 0, 3, 153, 1, 197, 1, 0, 3, 73, 1, 255, 3, 197, 1, 0, 38, }; -static const unsigned char _52[] PROGMEM = { -0, 32, 73, 1, 255, 1, 36, 1, 0, 6, 255, 2, 36, 1, 0, 5, 153, 1, 255, 2, 36, 1, 0, 4, 36, 1, 255, 1, 111, 1, 255, 1, 36, 1, 0, 4, 197, 1, 111, 1, 73, 1, 255, 1, 36, 1, 0, 3, 111, 1, 197, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 197, 1, 111, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 7, 111, 1, 0, 5, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 37, }; -static const unsigned char _53[] PROGMEM = { -0, 29, 153, 1, 255, 5, 0, 3, 255, 1, 111, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 73, 1, 255, 1, 0, 7, 111, 1, 197, 1, 255, 3, 197, 1, 0, 3, 153, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 8, 255, 1, 111, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 111, 1, 255, 1, 0, 3, 111, 1, 197, 1, 0, 3, 73, 1, 255, 3, 153, 1, 0, 38, }; -static const unsigned char _54[] PROGMEM = { -0, 30, 255, 4, 0, 4, 255, 1, 36, 1, 0, 2, 197, 1, 255, 1, 0, 2, 153, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 6, 36, 1, 255, 1, 73, 1, 153, 1, 255, 3, 0, 2, 36, 1, 255, 2, 111, 1, 0, 2, 111, 1, 255, 1, 0, 1, 36, 1, 255, 1, 197, 1, 0, 4, 255, 1, 111, 1, 36, 1, 255, 1, 111, 1, 0, 4, 255, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 4, 255, 1, 153, 1, 0, 1, 197, 2, 0, 4, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 111, 1, 197, 1, 0, 4, 255, 3, 197, 1, 0, 38, }; -static const unsigned char _55[] PROGMEM = { -0, 28, 197, 1, 255, 6, 153, 1, 0, 6, 153, 1, 255, 1, 36, 1, 0, 5, 73, 1, 255, 1, 111, 1, 0, 6, 197, 2, 0, 6, 73, 1, 255, 1, 73, 1, 0, 6, 153, 1, 255, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 153, 1, 255, 1, 0, 7, 197, 1, 153, 1, 0, 7, 255, 1, 111, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 40, }; -static const unsigned char _56[] PROGMEM = { -0, 30, 255, 4, 0, 4, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 2, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 36, 1, 0, 3, 197, 1, 255, 2, 197, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 73, 1, 0, 1, 197, 2, 0, 4, 153, 1, 197, 1, 0, 1, 255, 1, 153, 1, 0, 4, 111, 1, 255, 1, 0, 1, 197, 2, 0, 4, 153, 1, 197, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 4, 36, 1, 0, 37, }; -static const unsigned char _57[] PROGMEM = { -0, 29, 36, 1, 255, 3, 111, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 255, 1, 153, 1, 0, 2, 197, 2, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 255, 1, 153, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 197, 2, 0, 3, 73, 1, 255, 1, 153, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 255, 2, 153, 1, 0, 2, 73, 1, 255, 3, 36, 1, 197, 1, 111, 1, 0, 7, 255, 1, 73, 1, 0, 6, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 3, 197, 1, 255, 3, 73, 1, 0, 38, }; -static const unsigned char _58[] PROGMEM = { -0, 32, 255, 1, 153, 1, 0, 38, 255, 1, 153, 1, 0, 21, }; -static const unsigned char _59[] PROGMEM = { -0, 32, 255, 1, 153, 1, 0, 38, 255, 1, 153, 1, 0, 3, 36, 1, 153, 1, 0, 3, 111, 2, 0, 3, 197, 1, 0, 7, }; -static const unsigned char _60[] PROGMEM = { -0, 48, 153, 1, 73, 1, 0, 6, 153, 1, 255, 2, 73, 1, 0, 4, 153, 1, 255, 3, 36, 1, 0, 3, 153, 1, 255, 2, 111, 1, 0, 5, 153, 1, 255, 1, 0, 9, 153, 1, 255, 2, 111, 1, 0, 8, 153, 1, 255, 3, 36, 1, 0, 7, 153, 1, 255, 2, 73, 1, 0, 8, 153, 1, 73, 1, 0, 60, }; -static const unsigned char _61[] PROGMEM = { -0, 71, 153, 1, 255, 7, 73, 1, 0, 31, 153, 1, 255, 7, 73, 1, 0, 70, }; -static const unsigned char _62[] PROGMEM = { -0, 41, 153, 1, 73, 1, 0, 8, 153, 1, 255, 2, 73, 1, 0, 7, 111, 1, 255, 3, 73, 1, 0, 8, 197, 1, 255, 2, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 5, 197, 1, 255, 2, 73, 1, 0, 3, 111, 1, 255, 3, 73, 1, 0, 4, 153, 1, 255, 2, 73, 1, 0, 6, 153, 1, 73, 1, 0, 67, }; -static const unsigned char _63[] PROGMEM = { -0, 29, 36, 1, 255, 4, 0, 3, 36, 1, 255, 1, 111, 1, 0, 2, 197, 1, 255, 1, 0, 2, 153, 1, 197, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 153, 1, 0, 4, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 6, 197, 1, 255, 1, 0, 6, 197, 1, 255, 1, 36, 1, 0, 5, 153, 1, 255, 1, 36, 1, 0, 6, 255, 1, 153, 1, 0, 7, 255, 1, 111, 1, 0, 15, 73, 1, 255, 1, 111, 1, 0, 39, }; -static const unsigned char _64[] PROGMEM = { -0, 57, 153, 1, 255, 5, 73, 1, 0, 8, 111, 1, 255, 1, 153, 1, 0, 4, 36, 1, 255, 2, 36, 1, 0, 5, 153, 1, 255, 1, 0, 8, 111, 1, 255, 1, 0, 4, 73, 1, 255, 1, 0, 3, 255, 3, 36, 1, 197, 1, 153, 1, 0, 1, 153, 2, 0, 3, 197, 1, 111, 1, 0, 1, 36, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 2, 111, 1, 0, 1, 36, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 0, 2, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 73, 1, 0, 2, 255, 1, 73, 1, 0, 1, 111, 1, 153, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 2, 197, 1, 73, 1, 0, 1, 153, 1, 111, 1, 0, 1, 111, 1, 255, 1, 0, 4, 111, 1, 255, 1, 0, 3, 255, 1, 36, 1, 0, 1, 153, 1, 111, 1, 0, 1, 153, 1, 255, 1, 0, 4, 197, 1, 153, 1, 0, 2, 73, 1, 255, 1, 0, 2, 153, 1, 111, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 255, 1, 73, 1, 0, 2, 111, 1, 197, 1, 0, 2, 255, 1, 153, 1, 0, 1, 36, 1, 255, 2, 73, 1, 0, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 2, 197, 1, 0, 1, 255, 3, 73, 1, 0, 5, 197, 1, 153, 1, 0, 10, 36, 1, 255, 1, 111, 1, 0, 3, 255, 1, 153, 1, 0, 9, 255, 1, 153, 1, 0, 5, 255, 2, 111, 1, 0, 5, 153, 1, 255, 1, 153, 1, 0, 8, 197, 1, 255, 5, 153, 1, 0, 4, }; -static const unsigned char _65[] PROGMEM = { -0, 37, 73, 1, 255, 2, 0, 8, 197, 1, 153, 1, 255, 1, 111, 1, 0, 6, 36, 1, 255, 1, 73, 1, 197, 2, 0, 6, 153, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 5, 255, 1, 153, 1, 0, 2, 255, 1, 153, 1, 0, 4, 73, 1, 255, 1, 73, 1, 0, 2, 153, 1, 255, 1, 0, 4, 197, 2, 0, 3, 73, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 7, 197, 1, 0, 2, 153, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 255, 1, 153, 1, 0, 5, 36, 1, 255, 1, 153, 1, 73, 1, 255, 1, 73, 1, 0, 6, 153, 1, 255, 1, 197, 2, 0, 7, 73, 1, 255, 1, 0, 44, }; -static const unsigned char _66[] PROGMEM = { -0, 34, 73, 1, 255, 6, 153, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 153, 1, 197, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 7, 73, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 197, 1, 255, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 255, 1, 197, 1, 0, 2, 73, 1, 255, 6, 153, 1, 0, 46, }; -static const unsigned char _67[] PROGMEM = { -0, 40, 153, 1, 255, 4, 36, 1, 0, 4, 36, 1, 255, 1, 197, 1, 0, 3, 111, 1, 255, 1, 111, 1, 0, 3, 197, 2, 0, 5, 153, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 36, 2, 0, 2, 153, 1, 255, 1, 36, 1, 0, 9, 153, 1, 255, 1, 0, 10, 153, 1, 255, 1, 0, 10, 111, 1, 255, 1, 36, 1, 0, 9, 73, 1, 255, 1, 73, 1, 0, 5, 36, 1, 255, 1, 153, 1, 0, 2, 197, 2, 0, 5, 111, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 197, 1, 0, 3, 111, 1, 255, 1, 111, 1, 0, 5, 197, 1, 255, 4, 36, 1, 0, 50, }; -static const unsigned char _68[] PROGMEM = { -0, 37, 73, 1, 255, 6, 197, 1, 0, 4, 73, 1, 255, 1, 73, 1, 0, 4, 197, 1, 255, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 5, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 153, 1, 255, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 5, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 255, 2, 0, 3, 73, 1, 255, 6, 153, 1, 0, 51, }; -static const unsigned char _69[] PROGMEM = { -0, 34, 73, 1, 255, 8, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 7, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 8, 111, 1, 0, 44, }; -static const unsigned char _70[] PROGMEM = { -0, 31, 73, 1, 255, 7, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 6, 73, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 7, 73, 1, 255, 1, 73, 1, 0, 46, }; -static const unsigned char _71[] PROGMEM = { -0, 40, 197, 1, 255, 4, 36, 1, 0, 4, 36, 1, 255, 1, 197, 1, 0, 3, 111, 1, 255, 1, 111, 1, 0, 3, 255, 1, 197, 1, 0, 5, 111, 1, 255, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 5, 36, 1, 153, 1, 36, 1, 0, 1, 153, 1, 255, 1, 0, 10, 197, 2, 0, 10, 197, 2, 0, 3, 73, 1, 255, 4, 111, 1, 0, 1, 153, 1, 255, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 5, 36, 1, 255, 1, 111, 1, 0, 2, 255, 1, 153, 1, 0, 5, 36, 1, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 197, 1, 0, 3, 73, 1, 255, 2, 36, 1, 0, 4, 153, 1, 255, 4, 73, 1, 0, 50, }; -static const unsigned char _72[] PROGMEM = { -0, 34, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 8, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 44, }; -static const unsigned char _73[] PROGMEM = { -0, 17, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 21, }; -static const unsigned char _74[] PROGMEM = { -0, 33, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 7, 197, 2, 0, 2, 255, 1, 111, 1, 0, 3, 197, 2, 0, 2, 255, 1, 153, 1, 0, 3, 197, 1, 153, 1, 0, 2, 111, 1, 255, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 3, 153, 1, 255, 3, 73, 1, 0, 38, }; -static const unsigned char _75[] PROGMEM = { -0, 34, 73, 1, 255, 1, 73, 1, 0, 4, 36, 1, 255, 2, 0, 1, 73, 1, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 111, 1, 0, 4, 73, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 5, 73, 1, 255, 1, 73, 1, 255, 2, 197, 1, 0, 5, 73, 1, 255, 2, 111, 2, 255, 1, 153, 1, 0, 4, 73, 1, 255, 1, 153, 1, 0, 2, 197, 1, 255, 1, 73, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 2, 36, 1, 255, 2, 0, 3, 73, 1, 255, 1, 73, 1, 0, 3, 111, 1, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 255, 2, 0, 44, }; -static const unsigned char _76[] PROGMEM = { -0, 28, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 6, 197, 1, 0, 36, }; -static const unsigned char _77[] PROGMEM = { -0, 40, 153, 1, 255, 1, 197, 1, 0, 5, 36, 1, 255, 2, 0, 2, 153, 1, 255, 2, 36, 1, 0, 4, 73, 1, 255, 2, 0, 2, 153, 1, 255, 1, 153, 1, 73, 1, 0, 4, 153, 2, 255, 1, 0, 2, 153, 1, 255, 1, 73, 1, 153, 1, 0, 4, 255, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 1, 255, 1, 0, 3, 73, 1, 153, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 1, 197, 1, 73, 1, 0, 2, 153, 1, 111, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 1, 111, 1, 153, 1, 0, 2, 255, 1, 36, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 1, 36, 1, 255, 1, 0, 1, 73, 1, 197, 1, 0, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 2, 197, 1, 73, 1, 153, 1, 111, 1, 0, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 2, 153, 1, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 2, 73, 1, 255, 1, 197, 1, 0, 2, 73, 1, 255, 1, 0, 2, 153, 1, 255, 1, 0, 3, 255, 1, 153, 1, 0, 2, 73, 1, 255, 1, 0, 53, }; -static const unsigned char _78[] PROGMEM = { -0, 34, 111, 1, 255, 1, 111, 1, 0, 4, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 2, 0, 4, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 153, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 1, 153, 2, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 2, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 2, 111, 1, 197, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 255, 1, 73, 2, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 197, 1, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 4, 197, 2, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 4, 73, 1, 255, 2, 36, 1, 0, 1, 111, 1, 255, 1, 0, 5, 153, 1, 255, 1, 36, 1, 0, 44, }; -static const unsigned char _79[] PROGMEM = { -0, 40, 255, 4, 153, 1, 0, 5, 73, 1, 255, 1, 153, 1, 0, 3, 255, 2, 0, 4, 255, 1, 153, 1, 0, 5, 255, 1, 153, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 1, 153, 1, 255, 1, 0, 6, 73, 1, 255, 1, 73, 1, 0, 1, 197, 2, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 197, 2, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 153, 1, 255, 1, 0, 6, 73, 1, 255, 1, 73, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 2, 255, 1, 153, 1, 0, 5, 255, 1, 153, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 3, 255, 2, 0, 6, 197, 1, 255, 3, 111, 1, 0, 51, }; -static const unsigned char _80[] PROGMEM = { -0, 34, 73, 1, 255, 7, 36, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 36, 1, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 5, 255, 1, 153, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 36, 1, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 4, 197, 1, 255, 1, 0, 2, 73, 1, 255, 7, 0, 3, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 8, 73, 1, 255, 1, 73, 1, 0, 51, }; -static const unsigned char _81[] PROGMEM = { -0, 40, 255, 4, 111, 1, 0, 5, 111, 1, 255, 1, 111, 1, 0, 3, 255, 2, 0, 3, 36, 1, 255, 1, 111, 1, 0, 5, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 6, 111, 1, 255, 1, 36, 1, 0, 1, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 153, 1, 0, 6, 36, 1, 255, 1, 111, 1, 0, 1, 153, 1, 255, 1, 0, 6, 111, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 36, 1, 255, 1, 197, 1, 0, 3, 111, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 2, 36, 1, 0, 5, 255, 7, 73, 1, 0, 10, 73, 1, 111, 1, 0, 36, }; -static const unsigned char _82[] PROGMEM = { -0, 34, 111, 1, 255, 6, 197, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 111, 1, 255, 6, 153, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 2, 153, 1, 255, 1, 36, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 197, 1, 255, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 153, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 1, 73, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 5, 255, 2, 0, 44, }; -static const unsigned char _83[] PROGMEM = { -0, 36, 153, 1, 255, 4, 73, 1, 0, 4, 255, 1, 197, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 9, 255, 2, 36, 1, 0, 9, 255, 4, 111, 1, 0, 9, 153, 1, 255, 2, 111, 1, 0, 9, 111, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 6, 255, 1, 111, 1, 0, 1, 153, 1, 255, 1, 0, 5, 36, 1, 255, 1, 73, 1, 0, 2, 255, 2, 36, 1, 0, 3, 255, 1, 197, 1, 0, 4, 153, 1, 255, 4, 111, 1, 0, 46, }; -static const unsigned char _84[] PROGMEM = { -0, 27, 255, 9, 0, 4, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 7, 255, 1, 153, 1, 0, 39, }; -static const unsigned char _85[] PROGMEM = { -0, 34, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 4, 111, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 4, 153, 1, 197, 1, 0, 3, 153, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 73, 1, 0, 4, 111, 1, 255, 4, 36, 1, 0, 46, }; -static const unsigned char _86[] PROGMEM = { -0, 33, 111, 1, 255, 1, 73, 1, 0, 6, 111, 1, 255, 1, 0, 1, 255, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 1, 153, 1, 255, 1, 0, 5, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 4, 153, 1, 197, 1, 0, 3, 197, 1, 153, 1, 0, 4, 255, 1, 111, 1, 0, 3, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 2, 153, 2, 0, 5, 153, 2, 0, 1, 36, 1, 255, 1, 73, 1, 0, 5, 73, 1, 255, 1, 36, 1, 111, 1, 255, 1, 0, 7, 255, 1, 111, 1, 197, 1, 111, 1, 0, 7, 111, 1, 255, 2, 36, 1, 0, 7, 36, 1, 255, 1, 197, 1, 0, 48, }; -static const unsigned char _87[] PROGMEM = { -0, 51, 73, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 2, 0, 5, 153, 1, 255, 1, 0, 1, 255, 1, 153, 1, 0, 4, 153, 1, 255, 2, 73, 1, 0, 4, 255, 1, 153, 1, 0, 1, 197, 2, 0, 4, 255, 1, 111, 1, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 2, 36, 1, 255, 1, 73, 1, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 2, 197, 2, 0, 3, 197, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 2, 255, 1, 111, 1, 0, 2, 255, 1, 111, 1, 0, 3, 153, 1, 197, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 153, 1, 197, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 111, 1, 255, 1, 0, 5, 255, 1, 73, 1, 153, 1, 197, 1, 0, 4, 255, 1, 73, 1, 197, 1, 153, 1, 0, 5, 197, 1, 153, 1, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 255, 1, 73, 1, 0, 5, 111, 1, 255, 2, 36, 1, 0, 4, 111, 1, 255, 2, 0, 6, 36, 1, 255, 1, 197, 1, 0, 5, 36, 1, 255, 1, 153, 1, 0, 71, }; -static const unsigned char _88[] PROGMEM = { -0, 34, 197, 1, 255, 1, 36, 1, 0, 4, 36, 1, 255, 1, 197, 1, 0, 2, 255, 1, 197, 1, 0, 4, 197, 2, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 4, 153, 1, 255, 1, 36, 2, 255, 1, 73, 1, 0, 6, 197, 1, 153, 1, 197, 1, 153, 1, 0, 7, 36, 1, 255, 1, 197, 1, 0, 8, 111, 1, 255, 2, 73, 1, 0, 6, 73, 1, 255, 1, 73, 1, 153, 1, 255, 1, 36, 1, 0, 5, 255, 1, 153, 1, 0, 2, 255, 1, 197, 1, 0, 4, 197, 1, 255, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 111, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 36, 1, 111, 1, 255, 1, 153, 1, 0, 6, 255, 2, 0, 44, }; -static const unsigned char _89[] PROGMEM = { -0, 33, 111, 1, 255, 1, 153, 1, 0, 5, 36, 1, 255, 2, 0, 1, 153, 1, 255, 1, 73, 1, 0, 4, 153, 1, 255, 1, 36, 1, 0, 2, 255, 2, 0, 3, 73, 1, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 153, 1, 0, 2, 197, 2, 0, 5, 153, 1, 255, 1, 36, 1, 111, 1, 255, 1, 36, 1, 0, 6, 255, 3, 111, 1, 0, 7, 73, 1, 255, 1, 197, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 8, 36, 1, 255, 1, 111, 1, 0, 48, }; -static const unsigned char _90[] PROGMEM = { -0, 28, 153, 1, 255, 6, 197, 1, 0, 6, 73, 1, 255, 1, 111, 1, 0, 6, 255, 1, 197, 1, 0, 6, 111, 1, 255, 1, 36, 1, 0, 5, 36, 1, 255, 1, 111, 1, 0, 6, 197, 2, 0, 6, 111, 1, 255, 1, 36, 1, 0, 5, 36, 1, 255, 1, 111, 1, 0, 6, 197, 2, 0, 6, 73, 1, 255, 1, 73, 1, 0, 6, 255, 1, 153, 1, 0, 6, 73, 1, 255, 8, 0, 36, }; -static const unsigned char _91[] PROGMEM = { -0, 16, 111, 1, 255, 2, 153, 1, 0, 1, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 3, 111, 1, 255, 2, 153, 1, 0, 5, }; -static const unsigned char _93[] PROGMEM = { -0, 16, 255, 3, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 255, 3, 36, 1, 0, 5, }; -static const unsigned char _95[] PROGMEM = { -0, 153, 197, 1, 255, 8, 0, 9, }; -static const unsigned char _97[] PROGMEM = { -0, 56, 73, 1, 255, 4, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 111, 1, 255, 1, 0, 2, 197, 1, 153, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 4, 111, 1, 255, 3, 73, 1, 0, 1, 73, 1, 255, 3, 73, 1, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 3, 111, 1, 255, 1, 73, 1, 0, 1, 197, 1, 255, 1, 0, 2, 36, 1, 255, 2, 73, 1, 0, 2, 255, 4, 36, 1, 255, 1, 111, 1, 0, 36, }; -static const unsigned char _98[] PROGMEM = { -0, 28, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 153, 1, 255, 2, 197, 1, 0, 3, 153, 1, 255, 1, 153, 1, 0, 2, 197, 2, 0, 2, 153, 1, 255, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 153, 2, 0, 4, 197, 1, 153, 1, 0, 1, 153, 2, 0, 4, 197, 1, 153, 1, 0, 1, 153, 2, 0, 4, 255, 1, 111, 1, 0, 1, 153, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 153, 1, 255, 1, 111, 1, 0, 2, 197, 2, 0, 2, 153, 3, 255, 2, 197, 1, 0, 38, }; -static const unsigned char _99[] PROGMEM = { -0, 56, 36, 1, 255, 3, 111, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 2, 153, 1, 255, 1, 0, 3, 153, 1, 197, 1, 0, 2, 197, 1, 153, 1, 0, 7, 197, 1, 153, 1, 0, 7, 197, 1, 153, 1, 0, 7, 153, 1, 255, 1, 0, 3, 111, 1, 255, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 2, 255, 1, 111, 1, 0, 3, 36, 1, 255, 3, 111, 1, 0, 38, }; -static const unsigned char _100[] PROGMEM = { -0, 33, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 3, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 36, 1, 0, 1, 197, 1, 153, 1, 0, 3, 73, 1, 255, 1, 36, 2, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 36, 2, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 36, 2, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 36, 1, 0, 1, 197, 1, 153, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 255, 2, 36, 1, 0, 2, 73, 1, 255, 3, 111, 1, 255, 1, 36, 1, 0, 36, }; -static const unsigned char _101[] PROGMEM = { -0, 56, 36, 1, 255, 3, 197, 1, 0, 3, 36, 1, 255, 1, 111, 1, 0, 2, 197, 2, 0, 2, 197, 2, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 36, 1, 255, 7, 153, 1, 0, 1, 255, 1, 111, 1, 0, 7, 197, 2, 0, 4, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 153, 1, 255, 1, 0, 3, 36, 1, 255, 4, 0, 38, }; -static const unsigned char _102[] PROGMEM = { -0, 17, 73, 1, 255, 2, 0, 2, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 1, 73, 1, 255, 4, 0, 2, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 3, 255, 1, 111, 1, 0, 21, }; -static const unsigned char _103[] PROGMEM = { -0, 56, 73, 1, 255, 3, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 36, 1, 0, 1, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 36, 2, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 2, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 36, 2, 255, 1, 111, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 36, 1, 0, 2, 73, 1, 255, 3, 111, 1, 255, 1, 36, 1, 0, 6, 73, 1, 255, 1, 0, 2, 255, 1, 153, 1, 0, 3, 255, 1, 153, 1, 0, 2, 36, 1, 255, 4, 111, 1, 0, 11, }; -static const unsigned char _104[] PROGMEM = { -0, 28, 111, 1, 255, 1, 0, 7, 111, 1, 255, 1, 0, 7, 111, 1, 255, 1, 0, 7, 111, 1, 255, 1, 111, 1, 255, 3, 36, 1, 0, 2, 111, 1, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 36, }; -static const unsigned char _105[] PROGMEM = { -0, 13, 73, 1, 255, 1, 36, 1, 0, 9, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 16, }; -static const unsigned char _106[] PROGMEM = { -0, 10, 255, 1, 111, 1, 0, 7, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 36, 1, 255, 1, 73, 1, 255, 1, 197, 1, 0, 4, }; -static const unsigned char _107[] PROGMEM = { -0, 25, 197, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 2, 73, 1, 255, 1, 197, 1, 0, 1, 197, 1, 153, 1, 0, 2, 255, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 3, 197, 1, 153, 2, 255, 1, 0, 4, 197, 1, 255, 1, 111, 1, 255, 1, 111, 1, 0, 3, 197, 2, 0, 1, 153, 1, 255, 1, 36, 1, 0, 2, 197, 1, 153, 1, 0, 2, 255, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 2, 111, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 197, 1, 255, 1, 0, 32, }; -static const unsigned char _108[] PROGMEM = { -0, 10, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 1, 197, 1, 153, 1, 0, 12, }; -static const unsigned char _109[] PROGMEM = { -0, 79, 197, 1, 153, 2, 255, 2, 153, 1, 0, 1, 255, 3, 111, 1, 0, 2, 197, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 2, 36, 1, 0, 1, 111, 1, 255, 1, 36, 1, 0, 1, 197, 2, 0, 3, 255, 1, 153, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 73, 1, 0, 52, }; -static const unsigned char _110[] PROGMEM = { -0, 55, 111, 1, 197, 1, 73, 1, 255, 3, 36, 1, 0, 2, 111, 1, 255, 1, 153, 1, 0, 2, 153, 1, 255, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 36, }; -static const unsigned char _111[] PROGMEM = { -0, 56, 36, 1, 255, 3, 197, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 197, 2, 0, 2, 197, 2, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 4, 255, 1, 153, 1, 0, 1, 197, 2, 0, 3, 36, 1, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 111, 1, 0, 2, 197, 1, 255, 1, 0, 3, 36, 1, 255, 3, 197, 1, 0, 38, }; -static const unsigned char _112[] PROGMEM = { -0, 55, 153, 3, 255, 2, 197, 1, 0, 3, 153, 1, 255, 1, 153, 1, 0, 2, 197, 2, 0, 2, 153, 1, 255, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 153, 2, 0, 4, 255, 1, 111, 1, 0, 1, 153, 2, 0, 4, 255, 1, 153, 1, 0, 1, 153, 2, 0, 4, 255, 1, 111, 1, 0, 1, 153, 1, 197, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 153, 1, 255, 1, 111, 1, 0, 2, 255, 1, 197, 1, 0, 2, 153, 1, 197, 2, 255, 2, 153, 1, 0, 3, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 0, 7, 153, 1, 197, 1, 0, 15, }; -static const unsigned char _113[] PROGMEM = { -0, 56, 73, 1, 255, 3, 73, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 73, 1, 0, 1, 197, 1, 153, 1, 0, 3, 111, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 73, 1, 36, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 255, 1, 111, 1, 0, 3, 36, 1, 255, 1, 73, 1, 0, 1, 197, 2, 0, 3, 111, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 2, 73, 1, 0, 2, 36, 1, 255, 3, 111, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 6, 36, 1, 255, 1, 73, 1, 0, 9, }; -static const unsigned char _114[] PROGMEM = { -0, 37, 73, 1, 255, 1, 111, 1, 255, 2, 0, 1, 73, 1, 255, 1, 197, 1, 0, 3, 73, 1, 255, 1, 73, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 26, }; -static const unsigned char _115[] PROGMEM = { -0, 50, 255, 4, 73, 1, 0, 2, 197, 1, 153, 1, 0, 2, 111, 1, 255, 1, 36, 1, 0, 1, 255, 1, 73, 1, 0, 6, 197, 1, 255, 1, 153, 1, 0, 6, 111, 1, 255, 3, 153, 1, 0, 6, 111, 1, 255, 1, 153, 1, 0, 6, 197, 1, 153, 1, 0, 1, 255, 1, 111, 1, 0, 2, 36, 1, 255, 1, 111, 1, 0, 1, 36, 1, 255, 4, 111, 1, 0, 33, }; -static const unsigned char _116[] PROGMEM = { -0, 13, 36, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 1, 197, 1, 255, 3, 0, 1, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 153, 1, 197, 1, 0, 2, 36, 1, 255, 2, 0, 16, }; -static const unsigned char _117[] PROGMEM = { -0, 55, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 73, 1, 255, 1, 36, 1, 0, 1, 111, 1, 255, 1, 0, 3, 111, 1, 255, 1, 36, 1, 0, 1, 73, 1, 255, 1, 73, 1, 0, 2, 255, 2, 36, 1, 0, 2, 111, 1, 255, 3, 36, 1, 255, 1, 36, 1, 0, 36, }; -static const unsigned char _118[] PROGMEM = { -0, 42, 255, 1, 111, 1, 0, 4, 197, 1, 153, 1, 255, 1, 0, 3, 36, 1, 255, 1, 36, 1, 255, 1, 73, 1, 0, 2, 111, 1, 255, 1, 0, 1, 197, 1, 153, 1, 0, 2, 197, 1, 153, 1, 0, 1, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 1, 36, 1, 255, 1, 73, 1, 153, 1, 197, 1, 0, 3, 197, 1, 153, 1, 255, 1, 111, 1, 0, 3, 73, 1, 255, 2, 36, 1, 0, 4, 255, 1, 197, 1, 0, 30, }; -static const unsigned char _119[] PROGMEM = { -0, 66, 111, 1, 255, 1, 0, 3, 255, 1, 197, 1, 0, 2, 73, 1, 255, 1, 36, 1, 255, 1, 73, 1, 0, 1, 36, 1, 255, 2, 0, 2, 111, 1, 197, 1, 0, 1, 255, 1, 111, 1, 0, 1, 73, 1, 153, 1, 255, 1, 36, 1, 0, 1, 197, 1, 111, 1, 0, 1, 153, 1, 197, 1, 0, 1, 153, 1, 111, 1, 197, 1, 73, 1, 0, 1, 255, 1, 73, 1, 0, 1, 73, 1, 255, 1, 0, 1, 197, 1, 73, 1, 153, 2, 73, 1, 255, 1, 0, 2, 36, 1, 255, 1, 36, 1, 255, 1, 36, 1, 111, 1, 197, 1, 111, 1, 153, 1, 0, 3, 197, 3, 0, 1, 36, 1, 255, 1, 197, 1, 111, 1, 0, 3, 153, 1, 255, 1, 153, 1, 0, 2, 255, 2, 36, 1, 0, 3, 73, 1, 255, 1, 111, 1, 0, 2, 197, 1, 255, 1, 0, 46, }; -static const unsigned char _120[] PROGMEM = { -0, 42, 36, 1, 255, 1, 111, 1, 0, 2, 153, 1, 197, 1, 0, 1, 111, 1, 255, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 255, 1, 111, 1, 197, 1, 111, 1, 0, 3, 73, 1, 255, 2, 0, 5, 255, 1, 153, 1, 0, 4, 111, 1, 255, 2, 73, 1, 0, 2, 36, 1, 255, 1, 73, 1, 153, 1, 197, 1, 0, 2, 153, 2, 0, 2, 255, 1, 73, 2, 255, 1, 36, 1, 0, 2, 111, 1, 255, 1, 0, 28, }; -static const unsigned char _121[] PROGMEM = { -0, 54, 36, 1, 255, 1, 111, 1, 0, 4, 153, 1, 255, 1, 0, 1, 197, 2, 0, 4, 255, 1, 111, 1, 0, 1, 73, 1, 255, 1, 36, 1, 0, 2, 73, 1, 255, 1, 36, 1, 0, 2, 255, 1, 153, 1, 0, 2, 153, 2, 0, 3, 111, 1, 255, 1, 0, 1, 36, 1, 255, 1, 73, 1, 0, 3, 36, 1, 255, 1, 73, 1, 111, 1, 197, 1, 0, 5, 197, 1, 153, 1, 197, 1, 111, 1, 0, 5, 73, 1, 255, 2, 36, 1, 0, 6, 255, 1, 153, 1, 0, 7, 255, 1, 73, 1, 0, 6, 111, 1, 197, 1, 0, 5, 153, 1, 255, 2, 0, 14, }; -static const unsigned char _122[] PROGMEM = { -0, 49, 255, 6, 153, 1, 0, 5, 111, 1, 255, 1, 36, 1, 0, 4, 73, 1, 255, 1, 111, 1, 0, 5, 255, 1, 153, 1, 0, 5, 197, 1, 255, 1, 0, 5, 111, 1, 255, 1, 73, 1, 0, 4, 73, 1, 255, 1, 111, 1, 0, 5, 255, 1, 197, 1, 0, 5, 111, 1, 255, 7, 0, 32, }; -static const unsigned char _14849714[] PROGMEM = { -0, 59, 36, 1, 0, 16, 197, 1, 73, 1, 0, 14, 73, 1, 255, 1, 197, 1, 0, 14, 197, 1, 255, 2, 73, 1, 0, 12, 73, 1, 255, 3, 197, 1, 0, 12, 197, 1, 255, 4, 73, 1, 0, 10, 73, 1, 255, 5, 197, 1, 0, 10, 197, 1, 255, 6, 73, 1, 0, 8, 73, 1, 255, 7, 197, 1, 0, 8, 197, 1, 255, 8, 73, 1, 0, 6, 73, 1, 255, 9, 197, 1, 0, 6, 255, 11, 111, 1, 0, 70, }; -static const unsigned char _14849724[] PROGMEM = { -0, 53, 36, 1, 255, 11, 153, 1, 0, 5, 153, 1, 255, 10, 36, 1, 0, 5, 36, 1, 255, 9, 153, 1, 0, 7, 153, 1, 255, 8, 36, 1, 0, 7, 36, 1, 255, 7, 153, 1, 0, 9, 153, 1, 255, 6, 36, 1, 0, 9, 36, 1, 255, 5, 153, 1, 0, 11, 153, 1, 255, 4, 36, 1, 0, 11, 36, 1, 255, 3, 153, 1, 0, 13, 153, 1, 255, 2, 36, 1, 0, 13, 36, 1, 255, 1, 153, 1, 0, 15, 153, 1, 36, 1, 0, 75, }; -static LATTICE lattice_array[] = { - {32, 5, _32}, - {33, 5, _33}, - {35, 9, _35}, - {37, 15, _37}, - {39, 3, _39}, - {40, 6, _40}, - {41, 6, _41}, - {43, 10, _43}, - {44, 5, _44}, - {45, 6, _45}, - {46, 5, _46}, - {47, 5, _47}, - {48, 9, _48}, - {49, 9, _49}, - {50, 9, _50}, - {51, 9, _51}, - {52, 9, _52}, - {53, 9, _53}, - {54, 9, _54}, - {55, 9, _55}, - {56, 9, _56}, - {57, 9, _57}, - {58, 5, _58}, - {59, 5, _59}, - {60, 10, _60}, - {61, 10, _61}, - {62, 10, _62}, - {63, 9, _63}, - {64, 17, _64}, - {65, 11, _65}, - {66, 11, _66}, - {67, 12, _67}, - {68, 12, _68}, - {69, 11, _69}, - {70, 10, _70}, - {71, 12, _71}, - {72, 11, _72}, - {73, 5, _73}, - {74, 9, _74}, - {75, 11, _75}, - {76, 9, _76}, - {77, 13, _77}, - {78, 11, _78}, - {79, 12, _79}, - {80, 11, _80}, - {81, 12, _81}, - {82, 11, _82}, - {83, 11, _83}, - {84, 9, _84}, - {85, 11, _85}, - {86, 11, _86}, - {87, 17, _87}, - {88, 11, _88}, - {89, 11, _89}, - {90, 9, _90}, - {91, 5, _91}, - {93, 5, _93}, - {95, 9, _95}, - {97, 9, _97}, - {98, 9, _98}, - {99, 9, _99}, - {100, 9, _100}, - {101, 9, _101}, - {102, 5, _102}, - {103, 9, _103}, - {104, 9, _104}, - {105, 4, _105}, - {106, 3, _106}, - {107, 8, _107}, - {108, 3, _108}, - {109, 13, _109}, - {110, 9, _110}, - {111, 9, _111}, - {112, 9, _112}, - {113, 9, _113}, - {114, 6, _114}, - {115, 8, _115}, - {116, 4, _116}, - {117, 9, _117}, - {118, 7, _118}, - {119, 11, _119}, - {120, 7, _120}, - {121, 9, _121}, - {122, 8, _122}, - {14849714, 17, _14849714}, - {14849724, 17, _14849724}, -}; -extern const LATTICE_FONT_INFO Arial_19_GL; -const LATTICE_FONT_INFO Arial_19_GL ={ - 19, - 86, - lattice_array -}; From dc5da42ed117ef3be8d7cd4246c2fef793548080 Mon Sep 17 00:00:00 2001 From: Ryzee119 Date: Mon, 8 Aug 2022 15:48:45 +0930 Subject: [PATCH 121/121] Input: Add xinput lib --- src/lib/tusb_xinput | 1 + 1 file changed, 1 insertion(+) create mode 160000 src/lib/tusb_xinput diff --git a/src/lib/tusb_xinput b/src/lib/tusb_xinput new file mode 160000 index 00000000..a92a1e97 --- /dev/null +++ b/src/lib/tusb_xinput @@ -0,0 +1 @@ +Subproject commit a92a1e97e2ceffd81c1864fa21ff7b4d1a533053