@@ 0,0 1,126 @@
+# Image viewer - Low level USB device on STM32H747
+Author: František Boháček
+
+This project focuses on making a low level usb device - ie. working directly with the registers, as opposed to HALs.
+The goal is to make an application using CDC ACM to send images to the device, and show them on an LCD display connected
+through MIPI DSI interface. For usb USB OTG peripheral may be used, in high-speed mode, for the display DSI and LTDC peripherals
+can be utilized. To fit whole framebuffer in memory, external SDRAM present on the board is used.
+
+Because the focus of this work has been mostly on the USB OTG device, I used https://github.com/stm32-rs/stm32h7xx-hal a lot as inspiration,
+some parts may even be 'direct translation'.
+when writing SDRAM interfacing and DSI controller. It was very challenging to find information about the interface and display otherwise.
+Luckily this hal library has even examples for the STM32H747-DISCO board, so the individual display configuration and commands required
+to bring up the display, are present as well.
+
+## Project Structure
+
+The root project folder
+contains folders `linux_app`, where Rust Linux application resides,
+with typical structure for Rust crates, and `firmware`,
+where the STM32 firmware is located.
+
+As for `firmware` structure:
+- `devices` - Folder with support for various devices. It contains linker scripts, isr definitions,
+as well as a startup file that ensures bss is nulled, .data contains initialized code in ram, and calls main.
+- `include` - headers
+- `libs` - Third-party libraries. Specifically CMSIS for register definitions for both Cortex-M and STM32H7
+- `src` - C source code
+- `tests` - Tests runnable on Linux. Initially the author wanted to make more tests, where parts of the device
+would be simulated. But afterall there was no need for this, and only one test was made. Specifically,
+a test for seeing contents of device descriptor. The test utilizes that functions for sending data are used,
+and they are replaced by code that just prints to a file instead of changing chip memory.
+
+## USB device
+
+The usb device support is split across multiple files. `usb.h` contains
+USB protocol structures, and functions for general USB peripheral operations,
+like sending or receiving specific data. `usb_device.h` contains functions specific
+for initializing the device, for handling interrupts, and setup.
+`usb_device_cdc.h` contains implementation of CDC ACM.
+
+Care has been taken to properly abstract the usb send, reception, from
+setup and that from application layer. This means that it should be trivial
+to add support for other application layers besides USB CDC.
+
+Each application layer has its `vtable` consisting of pointers to
+a few functions that will be called from the 'controller' usb device when
+the device is enumerated. For example callbacks with new data available
+in fifo or setting up application-specific endpoints.
+
+Often the usb function implementations implement non-blocking aproach,
+where if the function would have to spin loop, it will just return
+WOULD_BLOCK. This ensures that no functions block, and it can be decided
+from upper layers what to do about that, like when to retry this operation.
+
+cdc acm implementation leverages queue for reception of data. It saves
+the data to queue, and then the application can receive the data from
+the queue. This is quite handy as the application doesn't need to implement
+some kind of a callback, but rather can just spin loop with `cdc_data_receive`.
+The data are put to the queue in usb interrupt.
+
+This is handy for smaller amounts of data, but for large amounts of data
+this has proven ineffective. For example, to upload a whole image (~ 2 MB),
+it could take even 30 seconds for an image to be received. The issue
+would arise every time size of the queue has been hit. Since at that point,
+the queue will fill completely. Then the app will read 512 bytes, and
+the queue will again get filled very quickly. So only last 512 bytes
+are causing this issue. To mitigate this issue, there is another
+possibility to receive data.
+
+The cdc application implements two possible callbacks,
+one being a callback that will receive the data without putting them to queue,
+but still, the data are first read to a variable, and have to be copied to framebuffer
+afterwards. Another possibility is to return a pointer that will say where to write the
+data to. In the first case it's possible to read only some data, but in the second
+the application always has to receive everything in the specified buffer.
+
+The final application combines these two mechanisms. First, character `i` is detected
+through the callback that receives copied data, and the data are copied to framebuffer.
+Following transmissions will instead be handled by the callback that returns pointer
+to where to save the data, and the data will be put to the framebuffer itself from
+the peripheral fifo directly!
+
+## Display
+
+Although the display driving is made out of two peripherals,
+support for both is contained in one file (`display.h`) and in the same functions.
+Additionally there is `otm8009a.h` that defines how to initialize the display
+used on the board.
+
+LTDC supports two modes, video mode and adapted command mode. In video mode
+data are continuously streamed to the display from framebuffer inside of RAM.
+In adapted command mode the application decides when to send data. Since
+the application is not updating the framebuffer, adapted command mode
+has been chosen. Although the display code contains support code for video
+mode, it has never been tried on hardware.
+
+## Usage
+
+## Building and flashing
+
+For building, makefile is available.
+It uses gcc cross toolchain for arm-none-eabi target.
+To build the application, run `make` in `firmware` folder.
+To flash it, `make flash` may be used. It uses `openocd`
+to flash the program.
+
+### Communication protocol on top of CDC ACM
+
+There is a simple ASCII based protocol supporting a few simple commands.
+
+r - turn screen to all red
+g - turn screen to all green
+b - turn screen to all blue
+l - toggle led
+i<IMG> - Upload an image and show it on the display. The IMG is expected to be in RGB888 format, ie. first three bytes show what's on the first pixel,
+first byte is intensity of R, second G, third B. The image is written row by row.
+
+### Application
+
+The computer application has been made in Rust.
+It is working on Linux, but nothing should be stopping
+it from working on Windows as well.
+The application is very simple, it accepts two cli arguments,
+the first one is path to the image to upload. The second one is
+path to TTY, default is /dev/ttyACM1.
+The application will upload the image specified, and exit.