├── .clang-format ├── .clang-tidy ├── .devcontainer ├── devcontainer.json └── docker-compose.yml ├── .github └── workflows │ ├── main-builder.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CMakeLists.txt ├── Dockerfile ├── LICENSE ├── README.md ├── docs └── images │ └── bootloader_v5.png ├── flash.mdbscript └── src ├── CMakeLists.txt ├── boot ├── CMakeLists.txt ├── boot_config.h ├── hardware_interrupt_table.S ├── interrupts.S ├── memory_partition.S ├── remapped_reset.S └── user_interrupt_table.S ├── bus ├── CMakeLists.txt ├── i2c │ ├── CMakeLists.txt │ ├── i2c.c │ └── i2c.h ├── spi │ ├── CMakeLists.txt │ ├── spi.c │ └── spi.h └── uart │ ├── CMakeLists.txt │ ├── uart.c │ └── uart.h ├── commands.c ├── commands.h ├── helpers ├── CMakeLists.txt ├── buffer.c ├── buffer.h ├── debug.c ├── debug.h ├── delay.c ├── delay.h ├── device.c ├── device.h ├── interval.c ├── interval.h ├── light.c ├── light.h ├── rtc.c └── rtc.h ├── instruments ├── CMakeLists.txt ├── logicanalyzer.c ├── logicanalyzer.h ├── multimeter.c ├── multimeter.h ├── oscilloscope.c ├── oscilloscope.h ├── powersource.c ├── powersource.h ├── sensors.c ├── sensors.h ├── wavegenerator.c └── wavegenerator.h ├── main.c ├── registers ├── CMakeLists.txt ├── comparators │ ├── CMakeLists.txt │ ├── cmp1.c │ ├── cmp1.h │ ├── cmp2.c │ ├── cmp2.h │ ├── cmp3.c │ ├── cmp3.h │ ├── cmp4.c │ ├── cmp4.h │ ├── cmp_params.c │ ├── cmp_params.h │ ├── cvr.c │ ├── cvr.h │ ├── ic1.c │ ├── ic1.h │ ├── ic2.c │ ├── ic2.h │ ├── ic3.c │ ├── ic3.h │ ├── ic4.c │ ├── ic4.h │ ├── ic_params.c │ ├── ic_params.h │ ├── oc1.c │ ├── oc1.h │ ├── oc2.c │ ├── oc2.h │ ├── oc3.c │ ├── oc3.h │ ├── oc4.c │ └── oc4.h ├── converters │ ├── CMakeLists.txt │ ├── adc1.c │ ├── adc1.h │ ├── adc_module_features.h │ ├── ctmu.c │ └── ctmu.h ├── memory │ ├── CMakeLists.txt │ ├── dma.c │ └── dma.h ├── system │ ├── CMakeLists.txt │ ├── clock.c │ ├── clock.h │ ├── interrupt_manager.c │ ├── interrupt_manager.h │ ├── pin_manager.c │ ├── pin_manager.h │ ├── system.c │ ├── system.h │ ├── system_types.h │ └── watchdog.h └── timers │ ├── CMakeLists.txt │ ├── timer_params.h │ ├── tmr1.c │ ├── tmr1.h │ ├── tmr2.c │ ├── tmr2.h │ ├── tmr3.c │ ├── tmr3.h │ ├── tmr4.c │ ├── tmr4.h │ ├── tmr5.c │ └── tmr5.h ├── sdcard ├── CMakeLists.txt ├── fatfs │ ├── 00history.txt │ ├── 00readme.txt │ ├── CMakeLists.txt │ ├── LICENSE.txt │ ├── diskio.c │ ├── diskio.h │ ├── fatfs_demo.c │ ├── fatfs_demo.h │ ├── ff.c │ ├── ff.h │ ├── ff_time.c │ ├── ffconf.h │ ├── ffsystem.c │ ├── ffunicode.c │ └── integer.h ├── sd_spi.c ├── sd_spi.h ├── sdcard.c └── sdcard.h ├── states.c └── states.h /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | IndentWidth: 4 3 | 4 | Language: Cpp 5 | 6 | # Yes: int *a; 7 | # No: int* a; 8 | # Absolutely not: int * a; 9 | DerivePointerAlignment: false 10 | PointerAlignment: Right 11 | 12 | # East const 13 | # Yes: int const a; 14 | # No: const int a; 15 | QualifierAlignment: Right 16 | 17 | # If parameters do not fit on one line, do this: 18 | # void func( 19 | # int a, 20 | # int b 21 | # ) 22 | AlignAfterOpenBracket: BlockIndent 23 | BinPackArguments: false 24 | BinPackParameters: false 25 | ExperimentalAutoDetectBinPacking: false 26 | AllowAllParametersOfDeclarationOnNextLine: false 27 | PenaltyReturnTypeOnItsOwnLine: 1000 28 | 29 | # Attach braces to surrounding context, except on functions. 30 | BreakBeforeBraces: Linux 31 | 32 | AllowShortLoopsOnASingleLine: true 33 | 34 | BitFieldColonSpacing: Before 35 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: [ 2 | bugprone*, 3 | 4 | cert*, 5 | 6 | cppcoreguidelines*, 7 | # Need globals to communicate with interrupts 8 | -cppcoreguidelines-avoid-non-const-global-variables, 9 | # Covered by readability-magic-numbers 10 | -cppcoreguidelines-avoid-magic-numbers, 11 | # We use global aggregates to dispatch extern registers. 12 | # This cannot cause order-of-initialization problems because 13 | # registers are guaranteed to be initialized at reset. 14 | -cppcoreguidelines-interfaces-global-init, 15 | 16 | google*, 17 | 18 | hicpp*, 19 | # Bad warning: https://stackoverflow.com/questions/50399090/use-of-a-signed-integer-operand-with-a-binary-bitwise-operator-when-using-un 20 | -hicpp-signed-bitwise, 21 | 22 | llvm*, 23 | # We use a different include guard style 24 | -llvm-header-guard, 25 | 26 | misc*, 27 | 28 | modernize*, 29 | 30 | performance*, 31 | 32 | readability*, 33 | ] 34 | 35 | CheckOptions: 36 | - key: bugprone-easily-swappable-parameters.ModelImplicitConversions 37 | value: false 38 | - key: readability-function-cognitive-complexity.Threshold 39 | value: '10' 40 | - key: readability-function-size.LineThreshold 41 | value: '80' 42 | 43 | - key: readability-identifier-length.MinimumParameterNameLength 44 | value: '1' 45 | - key: readability-identifier-length.IgnoredVariableNames 46 | value: '^dt|pu$' 47 | 48 | - key: readability-magic-numbers.IgnorePowersOf2IntegerValues 49 | value: 'true' 50 | - key: readability-magic-numbers.IgnoredIntegerValues 51 | value: '15;255;4095;65535;' 52 | 53 | # Empty loops should look like this: while (condition) continue; 54 | - key: readability-braces-around-statements.ShortStatementLines 55 | value: '1' 56 | - key: hicpp-braces-around-statements.ShortStatementLines 57 | value: '1' 58 | 59 | - key: readability-identifier-naming.EnumCase 60 | value: 'CamelCase' 61 | - key: readability-identifier-naming.FunctionCase 62 | value: 'lower_case' 63 | # Public functions have capitalized prefix 64 | - key: readability-identifier-naming.GlobalFunctionCase 65 | value: 'aNy_CasE' 66 | # Interrupt service routines 67 | - key: readability-identifier-naming.GlobalFunctionIgnoredRegexp 68 | value: '_[A-Z0-9]+Interrupt' 69 | - key: readability-identifier-naming.VariableCase 70 | value: 'lower_case' 71 | # Register names 72 | - key: readability-identifier-naming.VariableIgnoredRegexp 73 | value: '[A-Z][A-Z0-9]+(bits)?' 74 | - key: readability-identifier-naming.StructCase 75 | value: 'CamelCase' 76 | - key: readability-identifier-naming.TypedefCase 77 | value: 'CamelCase' 78 | - key: readability-identifier-naming.TypedefIgnoredRegexp 79 | value: '[A-Z]+_[a-zA-Z0-9]+' 80 | - key: readability-identifier-naming.EnumIgnoredRegexp 81 | value: '[A-Z]+_[a-zA-Z0-9]+' 82 | - key: readability-identifier-naming.StructIgnoredRegexp 83 | value: '[A-Z]+_[a-zA-Z0-9]+' 84 | - key: readability-identifier-naming.UnionIgnoredRegexp 85 | value: '[A-Z]+_[a-zA-Z0-9]+' 86 | - key: readability-identifier-naming.UnionCase 87 | value: 'CamelCase' 88 | - key: readability-identifier-naming.GlobalConstantCase 89 | value: 'UPPER_CASE' 90 | - key: readability-identifier-naming.GlobalConstantPrefix 91 | value: 'g_' 92 | - key: readability-identifier-naming.MacroDefinitionCase 93 | value: 'UPPER_CASE' 94 | 95 | FormatStyle: file 96 | SystemHeaders: false 97 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "dockerComposeFile": "./docker-compose.yml", 3 | "service": "app", 4 | "workspaceFolder": "/workspace", 5 | "remoteUser": "root" 6 | } -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | app: 5 | build: 6 | context: .. 7 | dockerfile: ./Dockerfile 8 | container_name: dev-firmware 9 | command: sleep infinity 10 | volumes: 11 | - ..:/workspace -------------------------------------------------------------------------------- /.github/workflows/main-builder.yml: -------------------------------------------------------------------------------- 1 | name: pslab-firmware 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | workflow_call: 9 | 10 | jobs: 11 | build: 12 | strategy: 13 | matrix: 14 | target: [v6, v5, v6_esp01] 15 | include: 16 | - target: v6 17 | branch: main 18 | cmake_flags: '-DCMAKE_BUILD_TYPE=RelWithDebInfo' 19 | - target: v5 20 | branch: main 21 | cmake_flags: '-DCMAKE_BUILD_TYPE=RelWithDebInfo -DLEGACY_HARDWARE=1' 22 | - target: v6_esp01 23 | branch: esp-01 24 | cmake_flags: '-DCMAKE_BUILD_TYPE=RelWithDebInfo' 25 | 26 | runs-on: ubuntu-latest 27 | steps: 28 | - name: Download project files 29 | uses: actions/checkout@v4 30 | with: 31 | ref: ${{ matrix.branch }} 32 | path: ${{ matrix.branch }} 33 | 34 | - name: Cache Compilers 35 | id: cache-compiler 36 | uses: actions/cache@v3 37 | with: 38 | path: ~/.cache/mplab-xc 39 | key: xc16-v2.10-cache 40 | 41 | - name: Download XC16 Compiler 42 | if: steps.cache-compiler.outputs.cache-hit != 'true' 43 | run: | 44 | mkdir -p ~/.cache/mplab-xc 45 | cd ~/.cache/mplab-xc 46 | wget https://ww1.microchip.com/downloads/aemDocuments/documents/DEV/ProductDocuments/SoftwareTools/xc16-v2.10-full-install-linux64-installer.run 47 | chmod +x xc16-v2.10-full-install-linux64-installer.run 48 | 49 | - name: Install XC16 Compiler 50 | run: | 51 | cd ~/.cache/mplab-xc 52 | sudo ./xc16-v2.10-full-install-linux64-installer.run --mode unattended --netservername dontknow 53 | 54 | - name: Set up cmake-microchip submodules 55 | run: | 56 | cd ${{ matrix.branch }} 57 | git submodule init 58 | git submodule update 59 | 60 | - name: Build firmware 61 | run: | 62 | cd ${{ matrix.branch }} 63 | mkdir build_${{ matrix.target }} 64 | cd build_${{ matrix.target }} 65 | cmake .. ${{ matrix.cmake_flags}} 66 | make 67 | 68 | - name: Fetch bootloader 69 | run: | 70 | git clone https://github.com/fossasia/pslab-bootloader.git pslab-bootloader 71 | cd pslab-bootloader 72 | mkdir build 73 | cd build 74 | wget https://github.com/fossasia/pslab-bootloader/releases/latest/download/pslab-bootloader.hex 75 | 76 | - name: Download XC8 Compiler 77 | if: steps.cache-compiler.outputs.cache-hit != 'true' 78 | run: | 79 | mkdir -p ~/.cache/mplab-xc 80 | cd ~/.cache/mplab-xc 81 | wget https://ww1.microchip.com/downloads/aemDocuments/documents/DEV/ProductDocuments/SoftwareTools/xc8-v3.00-full-install-linux-x64-installer.run 82 | chmod +x xc8-v3.00-full-install-linux-x64-installer.run 83 | 84 | - name: Install XC8 Compiler 85 | run: | 86 | cd ~/.cache/mplab-xc 87 | sudo ./xc8-v3.00-full-install-linux-x64-installer.run --mode unattended --netservername dontknow 88 | echo "/opt/microchip/xc8/v3.00/pic/bin" >> $GITHUB_PATH 89 | 90 | - name: Combine hex files 91 | run: | 92 | mv ${{ matrix.branch }}/build_${{ matrix.target }}/pslab-firmware.hex pslab-bootloader/build/pslab-firmware.hex 93 | cd pslab-bootloader 94 | chmod +x combine_hex.sh 95 | ./combine_hex.sh 96 | 97 | - name: Publish build files 98 | uses: actions/upload-artifact@v4 99 | with: 100 | name: pslab-firmware_${{ matrix.target}} 101 | path: pslab-bootloader/build/combined.hex 102 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '[0-9]+.[0-9]+.[0-9]+' 7 | 8 | jobs: 9 | set-body: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - run: sudo apt install pcregrep 14 | 15 | - uses: actions/checkout@v4 16 | 17 | - name: Parse changelog 18 | id: parse-changelog 19 | run: | 20 | tag='${{ github.ref_name }}' 21 | re_current_tag="## \[$tag\].*\n\n" # Match, but do not capture, current version tag, then... 22 | re_changes_body='((.|\n)+?)' # capture everything including newlines... 23 | re_previous_tag='## \[[0-9]+.[0-9]+.[0-9]+\]' # until previous version tag. 24 | re_full="${re_current_tag}${re_changes_body}${re_previous_tag}" 25 | echo 'match<> $GITHUB_OUTPUT 26 | # Match multiple lines, output capture group 1. 27 | pcregrep -M -o1 "$re_full" ./CHANGELOG.md >> $GITHUB_OUTPUT 28 | echo 'EOF' >> $GITHUB_OUTPUT 29 | 30 | - name: Set release body 31 | uses: softprops/action-gh-release@v2 32 | with: 33 | draft: true 34 | body: ${{ steps.parse-changelog.outputs.match }} 35 | 36 | build: 37 | uses: fossasia/pslab-firmware/.github/workflows/main-builder.yml@main 38 | 39 | attach-artifacts: 40 | needs: build 41 | 42 | runs-on: ubuntu-latest 43 | 44 | steps: 45 | - name: download 46 | uses: actions/download-artifact@v4 47 | 48 | - name: zip 49 | run: | 50 | zip -rj pslab-firmware_v6.zip pslab-firmware_v6/pslab-firmware.hex 51 | zip -rj pslab-firmware_v5.zip pslab-firmware_v5/pslab-firmware.hex 52 | zip -rj pslab-firmware_v6_esp01.zip pslab-firmware_v6_esp01/pslab-firmware.hex 53 | 54 | - name: attach 55 | uses: softprops/action-gh-release@v2 56 | with: 57 | draft: true 58 | files: pslab-firmware* 59 | fail_on_unmatched_files: true 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | .generated_files 4 | build* 5 | dist 6 | nbproject 7 | Makefile 8 | 9 | *.dump 10 | .vscode/* 11 | .idea/* 12 | 13 | *~* 14 | \#*\# 15 | .\#* 16 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/cmake-microchip"] 2 | path = external/cmake-microchip 3 | url = https://github.com/fossasia/cmake-microchip 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [3.1.0] - 2025-02-17 4 | 5 | ### Changed 6 | 7 | - Increase UART timeout ([`26de862`](https://github.com/fossasia/pslab-firmware/commit/26de86294997252c3c171e8be93c92410e57d354)) (Anashuman Singh) 8 | 9 | ### Added 10 | 11 | - Document how to build for v5 hardware ([`1a5da5a`](https://github.com/fossasia/pslab-firmware/commit/1a5da5acb5eba67291d622cb9e4953167786c91d)) (Marc Nause) 12 | 13 | ## [3.0.4] - 2025-01-05 14 | 15 | ### Fixed 16 | 17 | - Fix ACKSTAT missing from response in several I2C commands ([`6356eb2`](https://github.com/fossasia/pslab-firmware/commit/6356eb2656f856327c9090bcbd6e404db78ae2f0)) (Alexander Bessman) 18 | 19 | ## [3.0.3] - 2024-08-19 20 | 21 | ### Fixed 22 | 23 | - Fix UART2 pin mappings not matching labels ([`5728b36`](https://github.com/fossasia/pslab-firmware/commit/5728b36939f8dd76bfd83889c1cd94a57bab4329)) (Alexander Bessman) 24 | 25 | ## [3.0.2] - 2024-07-30 26 | 27 | ### Added 28 | 29 | - Add changelog (Alexander Bessman) 30 | 31 | ### Fixed 32 | 33 | - Fix `I2C_CommandReadBulk` reading one too many bytes ([`4ea85ec`](https://github.com/fossasia/pslab-firmware/commit/4ea85ec9ecda2f9ec4dcab0b56f0de5edb6fbfaa)) (Alexander Bessman) 34 | 35 | ## [3.0.1] - 2024-07-15 36 | 37 | ### Fixed 38 | 39 | - Fix broken capacitance measurement ([`36d4fd3`](https://github.com/fossasia/pslab-firmware/commit/36d4fd31fe6edc3845e16ab71af899f61262b061)) (Alexander Bessman) 40 | - Fix second half of sample buffer not being cleared ([`54034b8`](https://github.com/fossasia/pslab-firmware/commit/54034b81549d735af3ab5050bdcd06a08269a6b2)) (Alexander Bessman) 41 | 42 | ## [3.0.0] - 2024-01-15 43 | 44 | _Major refactorization of firmware._ 45 | 46 | [3.1.0]: https://github.com/fossasia/pslab-firmware/releases/tag/3.1.0 47 | [3.0.4]: https://github.com/fossasia/pslab-firmware/releases/tag/3.0.4 48 | [3.0.3]: https://github.com/fossasia/pslab-firmware/releases/tag/3.0.3 49 | [3.0.2]: https://github.com/fossasia/pslab-firmware/releases/tag/3.0.2 50 | [3.0.1]: https://github.com/fossasia/pslab-firmware/releases/tag/3.0.1 51 | [3.0.0]: https://github.com/fossasia/pslab-firmware/releases/tag/v3.0.0 52 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | set(CMAKE_TOOLCHAIN_FILE external/cmake-microchip/toolchain.cmake) 3 | set(MICROCHIP_MCU PIC24EP256GP204) 4 | 5 | project(PSLAB_FIRMWARE LANGUAGES C ASM) 6 | 7 | add_executable(pslab-firmware.elf) 8 | 9 | add_subdirectory(src) 10 | 11 | target_include_directories(pslab-firmware.elf 12 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 13 | 14 | target_compile_options(pslab-firmware.elf PRIVATE 15 | -Wall 16 | -Wextra 17 | -mno-eds-warn) 18 | 19 | target_link_options(pslab-firmware.elf PRIVATE 20 | "LINKER:-Map=pslab-firmware.map,--report-mem") 21 | 22 | if (LEGACY_HARDWARE) 23 | message("Building for PSLab v5") 24 | add_compile_definitions(V5_HW) 25 | else() 26 | message("Building for PSLab v6") 27 | endif(LEGACY_HARDWARE) 28 | 29 | if (ENABLE_DEBUG) 30 | message("Debug messages enabled") 31 | add_compile_definitions(PSLAB_DEBUG) 32 | endif(ENABLE_DEBUG) 33 | 34 | bin2hex(pslab-firmware.elf) 35 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | RUN apt-get update && apt-get install -y \ 4 | cmake \ 5 | make \ 6 | git \ 7 | wget \ 8 | && rm -rf /var/lib/apt/lists/* 9 | 10 | RUN wget -qO- https://ww1.microchip.com/downloads/aemDocuments/documents/DEV/ProductDocuments/SoftwareTools/xc16-v2.10-full-install-linux64-installer.run \ 11 | -O /tmp/xc16-installer.run && \ 12 | chmod +x /tmp/xc16-installer.run && \ 13 | /tmp/xc16-installer.run --mode unattended --prefix /opt/microchip/xc16/v2.10 --netservername "" && \ 14 | rm /tmp/xc16-installer.run 15 | -------------------------------------------------------------------------------- /docs/images/bootloader_v5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/pslab-firmware/37b91ab961409715fbfe7159a6a5aba1a0c3e364/docs/images/bootloader_v5.png -------------------------------------------------------------------------------- /flash.mdbscript: -------------------------------------------------------------------------------- 1 | device PIC24EP256GP204 2 | hwtool PICkit3 -p 3 | program build/pslab-firmware.hex 4 | sleep 1000 5 | reset 6 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(boot) 2 | add_subdirectory(bus) 3 | add_subdirectory(helpers) 4 | add_subdirectory(instruments) 5 | add_subdirectory(registers) 6 | add_subdirectory(sdcard) 7 | 8 | target_sources(pslab-firmware.elf PRIVATE 9 | commands.c 10 | main.c 11 | states.c) 12 | -------------------------------------------------------------------------------- /src/boot/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(pslab-firmware.elf PRIVATE 2 | hardware_interrupt_table.S 3 | interrupts.S 4 | memory_partition.S 5 | remapped_reset.S 6 | user_interrupt_table.S 7 | ) 8 | -------------------------------------------------------------------------------- /src/boot/boot_config.h: -------------------------------------------------------------------------------- 1 | #ifndef BOOT_CONFIG_H 2 | #define BOOT_CONFIG_H 3 | 4 | #define BOOT_CONFIG_PROGRAMMABLE_ADDRESS_LOW 0x1800 5 | 6 | #define BOOT_CONFIG_PROGRAMMABLE_ADDRESS_HIGH 0x2A7FE 7 | 8 | #define BOOT_CONFIG_VERIFICATION_APPLICATION_HEADER_SIZE 0 9 | 10 | #define BOOT_CONFIG_APPLICATION_IMAGE_APPLICATION_HEADER_ADDRESS (BOOT_CONFIG_PROGRAMMABLE_ADDRESS_LOW) 11 | 12 | #define BOOT_CONFIG_APPLICATION_RESET_ADDRESS (BOOT_CONFIG_PROGRAMMABLE_ADDRESS_LOW + BOOT_CONFIG_VERIFICATION_APPLICATION_HEADER_SIZE) 13 | 14 | #define BOOT_CONFIG_USER_IVT_TABLE_ADDRESS 0x1A00 15 | 16 | #define BOOT_CONFIG_VERSION 0x0102 17 | 18 | #define BOOT_CONFIG_MAX_PACKET_SIZE 0x100 19 | 20 | #endif -------------------------------------------------------------------------------- /src/boot/hardware_interrupt_table.S: -------------------------------------------------------------------------------- 1 | #include "boot_config.h" 2 | 3 | .equ remap_offset, 4 4 | 5 | .macro remap_to_application NAME 6 | .weak __\NAME 7 | .global __\NAME 8 | .equiv __\NAME, __remapped_DefaultInterrupt 9 | .section remapped\NAME, code, address(BOOT_CONFIG_USER_IVT_TABLE_ADDRESS+remap_offset), keep 10 | goto __\NAME 11 | .equ remap_offset, remap_offset + 4 12 | .endm 13 | 14 | .macro keep_in_bootloader NAME 15 | .endm 16 | 17 | .macro remap_to_application_default NAME 18 | .endm 19 | 20 | /* First entry in the remap table is the default interrupt, and it is 21 | * required and not implemented in hardware vectors, so we will implement 22 | * it here. */ 23 | .weak __remapped_DefaultInterrupt 24 | .global __remapped_DefaultInterrupt 25 | .section __remapped_DefaultInterrupt, code, address(BOOT_CONFIG_USER_IVT_TABLE_ADDRESS), keep 26 | goto __DefaultInterrupt 27 | 28 | /* All other entries are hardware vectors and can be selectively forwarded 29 | * by the user. Pull them in via the interrupt configuration file. */ 30 | #define REMAP_TABLE 31 | .include "src/boot/interrupts.S" 32 | -------------------------------------------------------------------------------- /src/boot/memory_partition.S: -------------------------------------------------------------------------------- 1 | /* This code will block out the space reserved by the boot loader so that the 2 | * application code can't link into that area. 3 | * 4 | * The value in the address() field defines the start address of the 5 | * boot code. 6 | * 7 | * The number on the .space defines the size of this block in PC units (2 per 8 | * instruction). 9 | */ 10 | #include "boot_config.h" 11 | .equ ERASE_PAGE_MASK,(~((2048) - 1)) 12 | .equ LAST_PAGE_START_ADDRESS, (0x2AFEA & ERASE_PAGE_MASK) 13 | 14 | 15 | .equ PROGRAM_MEMORY_ORIGIN, (0x200) 16 | 17 | .section *, code, address(PROGRAM_MEMORY_ORIGIN), noload, keep 18 | boot_loader_memory: 19 | .space (BOOT_CONFIG_PROGRAMMABLE_ADDRESS_LOW - PROGRAM_MEMORY_ORIGIN), 0x00 20 | 21 | .section *, code, address(LAST_PAGE_START_ADDRESS), noload, keep 22 | config_page_memory: 23 | .space (0x2AFEA-LAST_PAGE_START_ADDRESS), 0x00 24 | 25 | -------------------------------------------------------------------------------- /src/boot/remapped_reset.S: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/pslab-firmware/37b91ab961409715fbfe7159a6a5aba1a0c3e364/src/boot/remapped_reset.S -------------------------------------------------------------------------------- /src/boot/user_interrupt_table.S: -------------------------------------------------------------------------------- 1 | /* This file fills the hardware IVT table with the address of the corresponding 2 | * user remapped interrupt table. Thus when a hardware interrupt occurs, 3 | * the hardware interrupt vector will jump to the appropriate location in the 4 | * user/application interrupt table. That table will have a "goto _handler" 5 | * call that will call the appropriate handler function for the interrupt. 6 | */ 7 | 8 | #include "boot_config.h" 9 | 10 | /* If you have reached this line, then an interrupt triggered that should only 11 | * be available in the boot loader, not in the application. 12 | */ 13 | __bootload_interrupt_error: 14 | bra $ 15 | 16 | /* This section defines the interrupt vector table in hardware to map to the 17 | * user remap table. 18 | */ 19 | .equ remap_offset, 4 20 | 21 | .macro remap_to_application NAME 22 | .pword BOOT_CONFIG_USER_IVT_TABLE_ADDRESS+remap_offset 23 | .equ remap_offset, remap_offset+4 24 | .endm 25 | 26 | .macro keep_in_bootloader NAME 27 | .pword __bootload_interrupt_error 28 | .endm 29 | 30 | .macro remap_to_application_default NAME 31 | .pword BOOT_CONFIG_USER_IVT_TABLE_ADDRESS 32 | .endm 33 | 34 | /* 35 | * IVT section information. 36 | */ 37 | .section .ivt, code, address(0x4), keep 38 | 39 | #define REMAP_TABLE 40 | .include "src/boot/interrupts.S" 41 | -------------------------------------------------------------------------------- /src/bus/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(i2c) 2 | add_subdirectory(spi) 3 | add_subdirectory(uart) 4 | -------------------------------------------------------------------------------- /src/bus/i2c/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(pslab-firmware.elf PRIVATE 2 | i2c.c 3 | ) 4 | 5 | target_include_directories(pslab-firmware.elf 6 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 7 | -------------------------------------------------------------------------------- /src/bus/spi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(pslab-firmware.elf PRIVATE 2 | spi.c 3 | ) 4 | 5 | target_include_directories(pslab-firmware.elf 6 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 7 | 8 | -------------------------------------------------------------------------------- /src/bus/uart/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(pslab-firmware.elf PRIVATE 2 | uart.c 3 | ) 4 | 5 | target_include_directories(pslab-firmware.elf 6 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 7 | -------------------------------------------------------------------------------- /src/commands.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file commands.h 3 | * @brief Command handling. 4 | * 5 | */ 6 | 7 | #ifndef COMMANDS_H 8 | #define COMMANDS_H 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | /** 15 | * @brief Number of commands in each command group. 16 | * 17 | * This is used to set the dimensions of the command table, and to sanitize 18 | * received commands. 19 | */ 20 | #define NUM_PRIMARY_CMDS 14 21 | #define NUM_FLASH_CMDS 4 22 | #define NUM_ADC_CMDS 23 23 | #define NUM_SPI_CMDS 11 24 | #define NUM_I2C_CMDS 16 25 | #define NUM_UART2_CMDS 8 26 | #define NUM_DAC_CMDS 3 27 | #define NUM_WAVEGEN_CMDS 19 28 | #define NUM_DOUT_CMDS 1 29 | #define NUM_DIN_CMDS 2 30 | #define NUM_TIMING_CMDS 17 31 | #define NUM_COMMON_CMDS 27 32 | #define NUM_PASSTHRU_CMDS 1 33 | #define NUM_SENSOR_CMDS 9 34 | #define NUM_SDCARD_CMDS 3 35 | #define NUM_SECONDARY_CMDS_MAX NUM_COMMON_CMDS // Change if necessary. 36 | 37 | /** 38 | * @brief Acknowledge bytes. 39 | */ 40 | #define DO_NOT_BOTHER 0 // No response sent. 41 | #define SUCCESS 1 42 | #define ARGUMENT_ERROR 2 43 | #define FAILED 3 44 | 45 | typedef unsigned char command_t; /**< Type for command bytes. */ 46 | typedef unsigned char response_t; /**< Type for acknowledge bytes. */ 47 | 48 | /** 49 | * @brief Array containing the number of commands in each command group. 50 | */ 51 | extern command_t num_secondary_cmds[NUM_PRIMARY_CMDS + 1]; 52 | 53 | typedef response_t command_func_t(void); /**< Type for command functions. */ 54 | 55 | /** 56 | * @brief 2D array containing command functions. 57 | */ 58 | extern command_func_t* const cmd_table[NUM_PRIMARY_CMDS + 1][NUM_SECONDARY_CMDS_MAX + 1]; 59 | 60 | #ifdef __cplusplus 61 | } 62 | #endif 63 | 64 | #endif /* COMMANDS_H */ 65 | -------------------------------------------------------------------------------- /src/helpers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(pslab-firmware.elf PRIVATE 2 | buffer.c 3 | debug.c 4 | delay.c 5 | device.c 6 | interval.c 7 | light.c 8 | rtc.c 9 | ) 10 | 11 | target_include_directories(pslab-firmware.elf 12 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 13 | 14 | -------------------------------------------------------------------------------- /src/helpers/buffer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../bus/uart/uart.h" 3 | #include "../commands.h" 4 | #include "../registers/system/pin_manager.h" 5 | #include "buffer.h" 6 | 7 | // Space in memory to store data. 8 | uint16_t volatile __attribute__((section(".adc_buffer"), far)) BUFFER[BUFFER_SIZE]; 9 | 10 | response_t BUFFER_Retrieve(void) { 11 | 12 | uint16_t volatile* idx = &BUFFER[UART1_ReadInt()]; 13 | uint16_t volatile* end = idx + UART1_ReadInt(); 14 | 15 | LED_SetLow(); 16 | while (idx != end) UART1_WriteInt(*(idx++)); 17 | LED_SetHigh(); 18 | 19 | return SUCCESS; 20 | } 21 | 22 | response_t BUFFER_FetchInt(void) { 23 | 24 | uint16_t counter = UART1_ReadInt(); 25 | uint8_t channel = UART1_Read(); 26 | 27 | LED_SetLow(); 28 | uint16_t i; 29 | for (i = 0; i < counter; i++) { 30 | UART1_WriteInt(BUFFER[i + channel * (BUFFER_SIZE / 4)]); 31 | } 32 | LED_SetHigh(); 33 | 34 | return SUCCESS; 35 | } 36 | 37 | response_t BUFFER_FetchLong(void) { 38 | 39 | uint16_t counter = UART1_ReadInt(); 40 | uint8_t channel = UART1_Read(); 41 | 42 | LED_SetLow(); 43 | uint16_t i; 44 | for (i = 0; i < counter; i++) { 45 | UART1_WriteInt(BUFFER[i + 2 * channel * (BUFFER_SIZE / 4)]); 46 | UART1_WriteInt(BUFFER[i + (2 * channel + 1) * (BUFFER_SIZE / 4)]); 47 | } 48 | LED_SetHigh(); 49 | 50 | return SUCCESS; 51 | } 52 | 53 | response_t BUFFER_Fill(void) { 54 | 55 | uint16_t start = UART1_ReadInt(); 56 | uint16_t end = UART1_ReadInt(); 57 | 58 | uint16_t i; 59 | for (i = start; i < start + end; i++) { 60 | BUFFER[i] = UART1_ReadInt(); 61 | } 62 | 63 | return SUCCESS; 64 | } 65 | 66 | response_t BUFFER_Clear(void) { 67 | 68 | uint16_t start = UART1_ReadInt(); 69 | uint16_t end = UART1_ReadInt(); 70 | 71 | memset((void *) &BUFFER[start], 0, (end - start) * sizeof(int)); 72 | 73 | return SUCCESS; 74 | } 75 | -------------------------------------------------------------------------------- /src/helpers/buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef BUFFER_H 2 | #define BUFFER_H 3 | 4 | #include 5 | 6 | #define BUFFER_SIZE 10000 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | extern uint16_t volatile __attribute__((section(".adc_buffer"), far)) BUFFER[BUFFER_SIZE]; 13 | 14 | /** 15 | * @brief Send buffer contents. 16 | * 17 | * @description 18 | * This command function takes two arguments over serial: 19 | * 1. The starting index in the buffer from which to send values. 20 | * 2. The number of values to be sent. 21 | * It returns the requested data over serial. 22 | * It sends an acknowledge byte (SUCCESS) 23 | * 24 | * @return SUCCESS 25 | */ 26 | response_t BUFFER_Retrieve(void); 27 | 28 | /** 29 | * @brief Send buffer content as integers. 30 | * 31 | * @description 32 | * This command function takes two arguments over serial: 33 | * 1. The starting index in the buffer from which to send values. 34 | * 2. The number of values to be sent. 35 | * 36 | * It returns the requested data over serial. 37 | * It sends an acknowledge byte (SUCCESS) 38 | * 39 | * @return SUCCESS 40 | */ 41 | response_t BUFFER_FetchInt(void); 42 | 43 | /** 44 | * @brief Send buffer content as longs. 45 | * 46 | * @description 47 | * This command function takes two arguments over serial: 48 | * 1. The starting index in the buffer from which to send values. 49 | * 2. The number of values to be sent. 50 | * 51 | * It returns the requested data over serial. 52 | * It sends an acknowledge byte (SUCCESS) 53 | * 54 | * @return SUCCESS 55 | */ 56 | response_t BUFFER_FetchLong(void); 57 | 58 | /** 59 | * @brief Populate BUFFER array 60 | * 61 | * @description 62 | * This command function takes two arguments over serial: 63 | * 1. The starting index in the buffer from which to fill values. 64 | * 2. The number of values to be sent. 65 | * 66 | * It does not return anything over serial. 67 | * It sends an acknowledge byte (SUCCESS) 68 | * 69 | * @return SUCCESS 70 | */ 71 | response_t BUFFER_Fill(void); 72 | 73 | /** 74 | * @brief Clear BUFFER array 75 | * 76 | * @description 77 | * This command function takes two arguments over serial: 78 | * 1. The starting index in the buffer from which it should be emptied 79 | * 2. The number of indices need cleared. 80 | * 81 | * It does not return anything over serial. 82 | * It sends an acknowledge byte (SUCCESS) 83 | * 84 | * @return SUCCESS 85 | */ 86 | response_t BUFFER_Clear(void); 87 | 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | 92 | #endif /* BUFFER_H */ 93 | -------------------------------------------------------------------------------- /src/helpers/debug.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../bus/uart/uart.h" 4 | #include "../commands.h" 5 | #include "debug.h" 6 | 7 | response_t DEBUG_is_enabled(void) { 8 | #ifdef PSLAB_DEBUG 9 | bool const IS_DEBUG_ENABLED = true; 10 | #else 11 | bool const IS_DEBUG_ENABLED = false; 12 | #endif // PSLAB_DEBUG 13 | 14 | UART1_Write(IS_DEBUG_ENABLED); 15 | return DO_NOT_BOTHER; 16 | } 17 | -------------------------------------------------------------------------------- /src/helpers/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEBUG_H 2 | #define _DEBUG_H 3 | 4 | #include "../commands.h" 5 | 6 | // Enable debug messages over serial with -DENABLE_DEBUG CMake flag. 7 | 8 | #ifdef SERIAL_DEBUG 9 | #define DEBUG_write_u8(byte) UART1_Write(byte) 10 | #define DEBUG_write_u16(word) UART1_WriteInt(word) 11 | #define DEBUG_write_u32(dword) UART1_write_u32(dword) 12 | #else 13 | #define DEBUG_write_u8(byte) ((void)byte) 14 | #define DEBUG_write_u16(word) ((void)word) 15 | #define DEBUG_write_u32(dword) ((void)dword) 16 | #endif // SERIAL_DEBUG 17 | 18 | /** 19 | * @brief Tell host whether debug messages are enabled. 20 | * 21 | * @details If the firmware was built with -DENABLE_DEBUG, extra messages 22 | * containing information that may be useful in debugging are sent over 23 | * serial, in addition to the messages which are normally sent. The host 24 | * must take this into consideration when communicating with the PSLab, so 25 | * that the correct number of bytes are read for each transaction. 26 | * 27 | * @return is_debug_enabled bool 28 | * 29 | * @return DO_NOT_BOTHER response_t 30 | */ 31 | response_t DEBUG_is_enabled(void); 32 | 33 | #endif // _DEBUG_H 34 | -------------------------------------------------------------------------------- /src/helpers/delay.c: -------------------------------------------------------------------------------- 1 | #include "delay.h" 2 | #include 3 | 4 | void DELAY_ms(unsigned long d) { 5 | __delay_ms(d); 6 | } 7 | 8 | void DELAY_us(unsigned long d) { 9 | __delay_us(d); 10 | } 11 | -------------------------------------------------------------------------------- /src/helpers/delay.h: -------------------------------------------------------------------------------- 1 | #ifndef DELAY_H 2 | #define DELAY_H 3 | 4 | /** 5 | * @file delay.h 6 | * @brief Delay functions. 7 | * 8 | * This file contains wrapper functions for the compiler built in delay 9 | * functions. The reason for this is that other files which need to use delays 10 | * can include just a single file, delay.h, instead of needing to both define 11 | * FCY and import . 12 | */ 13 | 14 | #include "../registers/system/clock.h" 15 | 16 | #define FCY (_XTAL_FREQ / 2) 17 | 18 | void DELAY_ms(unsigned long d); 19 | void DELAY_us(unsigned long d); 20 | 21 | #endif /* DELAY_H */ 22 | -------------------------------------------------------------------------------- /src/helpers/device.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../bus/uart/uart.h" 5 | #include "../commands.h" 6 | #include "../registers/system/pin_manager.h" 7 | #include "../registers/system/watchdog.h" 8 | 9 | #define SEMVERS 3 10 | 11 | static uint8_t const VERSION_HW[] = 12 | #ifndef V5_HW 13 | "PSLab V6"; 14 | #else 15 | "PSLab V5"; 16 | #endif // V5_HW 17 | static union { 18 | struct { 19 | uint8_t const major; 20 | uint8_t const minor; 21 | uint8_t const patch; 22 | }; 23 | uint8_t const version[SEMVERS]; 24 | } const VERSION_FW = {{ 25 | .major = 3, 26 | .minor = 1, 27 | .patch = 0 28 | }}; 29 | 30 | response_t DEVICE_GetVersion(void) { 31 | for (size_t i = 0; i < sizeof(VERSION_HW) - 1; ++i) { 32 | UART1_Write(VERSION_HW[i]); 33 | } 34 | 35 | UART1_Write('\n'); 36 | 37 | return DO_NOT_BOTHER; 38 | } 39 | 40 | response_t DEVICE_get_fw_version(void) { 41 | for (size_t i = 0; i < SEMVERS; ++i) { 42 | UART1_Write(VERSION_FW.version[i]); 43 | } 44 | 45 | return DO_NOT_BOTHER; 46 | } 47 | 48 | response_t DEVICE_Reset(void) { 49 | __asm__ volatile ("reset"); 50 | 51 | return DO_NOT_BOTHER; 52 | } 53 | 54 | response_t DEVICE_ReadRegisterData(void) { 55 | uint16_t *address = (uint16_t *) (UART1_ReadInt() & 0xFFFF); 56 | UART1_WriteInt(*address); 57 | 58 | return SUCCESS; 59 | } 60 | 61 | response_t DEVICE_WriteRegisterData(void) { 62 | uint16_t *address = (uint16_t *) (UART1_ReadInt() & 0xFFFF); 63 | uint16_t data = UART1_ReadInt(); 64 | *address = data; 65 | 66 | return SUCCESS; 67 | } 68 | -------------------------------------------------------------------------------- /src/helpers/device.h: -------------------------------------------------------------------------------- 1 | #ifndef VERSION_H 2 | #define VERSION_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /** 9 | * @brief Get hardware version. 10 | * @return DO_NOT_BOTHER 11 | */ 12 | response_t DEVICE_GetVersion(void); 13 | 14 | /** 15 | * @brief Get firmware version. 16 | * @return MAJOR (uint8_t), MINOR (uint8_t), PATCH (uint8_t) 17 | */ 18 | response_t DEVICE_get_fw_version(void); 19 | 20 | /** 21 | * @brief Reset the device by moving program counter to 0x0000 22 | * @return DO_NOT_BOTHER 23 | */ 24 | response_t DEVICE_Reset(void); 25 | 26 | /** 27 | * @brief Read content from Special Function Registers 28 | * @return SUCCESS 29 | */ 30 | response_t DEVICE_ReadRegisterData(void); 31 | 32 | /** 33 | * @brief Write content to Special Function Registers given the register 34 | * address and data as two integers 35 | * @return SUCCESS 36 | */ 37 | response_t DEVICE_WriteRegisterData(void); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif /* VERSION_H */ 44 | -------------------------------------------------------------------------------- /src/helpers/interval.h: -------------------------------------------------------------------------------- 1 | #ifndef INTERVAL_H 2 | #define INTERVAL_H 3 | 4 | #include 5 | #include "../commands.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | /** 12 | * @brief Setup input capture on one channel 13 | * 14 | * @description 15 | * This routing will configure IC1,2 and DMA0,1 modules to listen to logic 16 | * level changes on a pin defined by the channel byte and log timer values 17 | * in BUFFER 1st and 2nd quarters. If trigger is set by the trig byte, this 18 | * will use IC4 module to listen to the trigger observation and time log will 19 | * then start. 20 | * It will combine both IC1 and IC2 modules to form a 32-bit timer which will 21 | * have support for more data points than `CaptureThree` and `CaptureFour` 22 | * routines. 23 | * 24 | * @param count : number of data points to capture 25 | * @param channel : the pin that needs to be monitored 26 | * @param mode : logic level variation. Refer to `IC_PARAMS_CAPTURE_MODE` 27 | * @param trig : en/disable trigger using IC4 28 | * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 29 | * | TRIG PIN | X | TRIG MODE | 30 | * 31 | * @return None 32 | */ 33 | void INTERVAL_CaptureOne(uint16_t count, uint8_t channel, uint8_t mode, uint8_t trig); 34 | 35 | /** 36 | * @brief Setup input capture on two channels 37 | * 38 | * @description 39 | * This routing will configure IC1,2,3,4 and DMA0,1,2,3 modules to listen to 40 | * logic level changes on pins defined by the channel byte and log timer 41 | * values in BUFFER. 42 | * It will combine both IC1, IC2 and IC3, IC4 modules to form a 32-bit timer 43 | * which will have support for more data points than `CaptureThree` and 44 | * `CaptureFour` routines. 45 | * 46 | * @param count : number of data points to capture 47 | * @param mode : logic level variation. Refer to `IC_PARAMS_CAPTURE_MODE` 48 | * @param channel : the pin that needs to be monitored 49 | * 50 | * @return None 51 | */ 52 | void INTERVAL_CaptureTwo(uint16_t count, uint8_t mode, uint8_t channel); 53 | 54 | /** 55 | * @brief Setup input capture on three channels 56 | * 57 | * @description 58 | * This routing will use IC1,2,3 modules with DMA0,1,2 channels to capture 59 | * logic level variations in LA1, LA2 and LA3 pins. These pins are fixed. 60 | * If trigger is set by the trig byte, this will use IC4 module to listen to 61 | * the trigger observation and time log will then start. 62 | * 63 | * @param count : number of data points to capture 64 | * @param mode : logic level variation. Refer to `IC_PARAMS_CAPTURE_MODE` 65 | * @param trig : en/disable trigger using IC4 66 | * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 67 | * | TRIG PIN | X | TRIG MODE | 68 | * 69 | * @return None 70 | */ 71 | void INTERVAL_CaptureThree(uint16_t count, uint16_t mode, uint8_t trig); 72 | 73 | /** 74 | * @brief Setup input capture on four channels 75 | * 76 | * @description 77 | * This routing will use IC1,2,3,4 modules with DMA0,1,2,3 channels to capture 78 | * logic level variations in LA1, LA2, LA3 and LA4 pins. These pins are fixed. 79 | * Timer 2 will be used as the timer source unlike the other three capture 80 | * methods that use peripheral clock as the timer source. 81 | * 82 | * @param count : number of data points to capture 83 | * @param mode : logic level variation. Refer to `IC_PARAMS_CAPTURE_MODE` 84 | * @param prescaler : pre-scaler value for timer 2 module 85 | * 86 | * @return None 87 | */ 88 | void INTERVAL_CaptureFour(uint16_t count, uint16_t mode, uint8_t prescaler); 89 | 90 | response_t INTERVAL_GetState(void); 91 | 92 | // Getters and setters 93 | 94 | void SetDIGITAL_STATES(uint8_t); 95 | void SetDefaultDIGITAL_STATES(void); 96 | uint8_t GetDIGITAL_STATES(void); 97 | 98 | void SetDefaultDIGITAL_STATES_ERROR(void); 99 | uint8_t GetDIGITAL_STATES_ERROR(void); 100 | 101 | #ifdef __cplusplus 102 | } 103 | #endif 104 | 105 | #endif /* INTERVAL_H */ 106 | 107 | -------------------------------------------------------------------------------- /src/helpers/light.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../bus/uart/uart.h" 3 | #include "../registers/system/interrupt_manager.h" 4 | #include "../registers/system/pin_manager.h" 5 | #include "light.h" 6 | 7 | #define SendZero(pin) do {\ 8 | pin = 1;\ 9 | __asm__ __volatile__("repeat #22");\ 10 | Nop();\ 11 | pin = 0;\ 12 | __asm__ __volatile__("repeat #51");\ 13 | Nop();\ 14 | } while(0) 15 | 16 | #define SendOne(pin) do {\ 17 | pin = 1;\ 18 | __asm__ __volatile__("repeat #45");\ 19 | Nop();\ 20 | pin = 0;\ 21 | __asm__ __volatile__("repeat #38");\ 22 | Nop();\ 23 | } while(0) 24 | 25 | #define SendLatch(pin) do {\ 26 | pin = 0;\ 27 | __asm__ volatile ("repeat #3264");\ 28 | Nop();\ 29 | } while(0) 30 | 31 | #define RGBCommon(red, green, blue, pin) do {\ 32 | uint8_t data[] = {green, red, blue};\ 33 | uint8_t location;\ 34 | \ 35 | SendLatch(pin);\ 36 | \ 37 | for (location = 0; location < 3; location++) {\ 38 | uint8_t bit;\ 39 | bit = data[location];\ 40 | uint8_t byte;\ 41 | for (byte = 0; byte < 8; byte++) {\ 42 | if (bit & 0x80) {\ 43 | SendOne(pin);\ 44 | } else {\ 45 | SendZero(pin);\ 46 | }\ 47 | bit = bit << 1;\ 48 | }\ 49 | }\ 50 | } while(0) 51 | 52 | typedef enum { 53 | ONBOARD, 54 | SQR1, 55 | SQR2, 56 | SQR3, 57 | SQR4, 58 | } PINSELECT; 59 | 60 | void LIGHT_RGB(uint8_t red, uint8_t green, uint8_t blue) { 61 | RGBCommon(red, green, blue, RGB_LED_Setter); 62 | } 63 | 64 | response_t LIGHT_RGBPin(void) { 65 | uint8_t count = UART1_Read(); 66 | uint8_t colors[count]; 67 | 68 | uint8_t i; 69 | for (i = 0; i < count; i++) { 70 | colors[i] = UART1_Read(); 71 | } 72 | PINSELECT pin = UART1_Read(); 73 | 74 | INTERRUPT_GlobalDisable(); 75 | 76 | for (i = 0; i < count; i = i + 3) { 77 | switch (pin) { 78 | case ONBOARD: 79 | RGBCommon(colors[i+1], colors[i], colors[i+2], RGB_LED_Setter); 80 | break; 81 | case SQR1: 82 | RGBCommon(colors[i+1], colors[i], colors[i+2], SQR1_Setter); 83 | break; 84 | case SQR2: 85 | RGBCommon(colors[i+1], colors[i], colors[i+2], SQR2_Setter); 86 | break; 87 | case SQR3: 88 | RGBCommon(colors[i+1], colors[i], colors[i+2], SQR3_Setter); 89 | break; 90 | case SQR4: 91 | RGBCommon(colors[i+1], colors[i], colors[i+2], SQR4_Setter); 92 | break; 93 | default: 94 | break; 95 | } 96 | } 97 | 98 | INTERRUPT_GlobalEnable(); 99 | 100 | return SUCCESS; 101 | } 102 | -------------------------------------------------------------------------------- /src/helpers/light.h: -------------------------------------------------------------------------------- 1 | #ifndef LIGHT_H 2 | #define LIGHT_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /** 9 | * @brief Control the color of RGB LED 10 | * 11 | * @description 12 | * Lights up the RGB LED. This method takes around 61.5 us to finish. 13 | * 14 | * @param 15 | * red: red color level (0-255) 16 | * green: green color level (0-255) 17 | * blue: blue color level (0-255) 18 | * 19 | * @example 20 | * Light_RGB(255, 0, 0); will light up red color 21 | */ 22 | void LIGHT_RGB(uint8_t red, uint8_t green, uint8_t blue); 23 | 24 | /** 25 | * @brief Controls the on-board RGB LED 26 | * 27 | * @description 28 | * This routine takes three types of arguments over serial. 29 | * 1. (uint8) count 30 | * Number of color levels. This has to be a multiple of 3 since each LED 31 | * has three colors to control. 32 | * 2. (uint8 [count]) color levels 33 | * This a sequence of bytes with the amount determined by count variable. 34 | * These will define red, green and blue colors of each of the LEDs. 35 | * 3. (uint8) pin 36 | * The pin to which the RGB LED's DIN is connected. 37 | * 0: Onboard RGB, 38 | * 1: SQ1, 39 | * 2: SQ2, 40 | * 3: SQ3, 41 | * 4: SQ4 42 | * 43 | * It will not return anything over serial. An acknowledgment will be passed. 44 | * 45 | * @return none 46 | */ 47 | response_t LIGHT_RGBPin(void); 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | 53 | #endif /* LIGHT_H */ 54 | -------------------------------------------------------------------------------- /src/helpers/rtc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../bus/i2c/i2c.h" 5 | #include "../bus/uart/uart.h" 6 | #include "../commands.h" 7 | #include "../registers/system/pin_manager.h" 8 | #include "delay.h" 9 | #include "light.h" 10 | #include "rtc.h" 11 | 12 | // This bit is used to enable the oscillator. When negated, the oscillator is disabled. 13 | static uint8_t const oscillator_enable = 0x7F; 14 | 15 | static uint8_t data_to_bcd(uint8_t data){ 16 | uint8_t bcd = data; 17 | 18 | if(data >= 10){ 19 | uint8_t left = data / 10; 20 | uint8_t right = data % 10; 21 | bcd = (left << 4) | right; 22 | } 23 | return bcd; 24 | } 25 | 26 | static uint8_t bcd_to_data(uint8_t bcd){ 27 | uint8_t right = (0xF & bcd); 28 | uint8_t left = (bcd >> 4) & 0xF; 29 | 30 | left *= 10; 31 | return left + right; 32 | } 33 | 34 | response_t RTC_SetTime(uint32_t const * const unix_timestamp) { 35 | 36 | time_t timestamp = (time_t) *unix_timestamp; 37 | struct tm *tm_info; 38 | 39 | tm_info = gmtime(×tamp); 40 | uint8_t sec = tm_info->tm_sec; 41 | uint8_t min = tm_info->tm_min; 42 | uint8_t hours = tm_info->tm_hour; 43 | uint8_t day = tm_info->tm_wday + 1; 44 | uint8_t date = tm_info->tm_mday; 45 | uint8_t month = tm_info->tm_mon + 1; 46 | uint8_t year = tm_info->tm_year % 100; // Tm_year starts from 00 which means(1900). 47 | // ds1307 only stores the last 2 digits. 48 | if(sec == 60) 49 | sec = 0; 50 | 51 | // Default 24 hrs format. 52 | uint8_t buffer[9]; 53 | buffer[0] = DS1307_DATA_REG_SECONDS; 54 | buffer[1] = data_to_bcd(sec) & oscillator_enable; // seconds 55 | buffer[2] = data_to_bcd(min); // minutes 56 | buffer[3] = data_to_bcd(hours); // hours (hrs format) 57 | buffer[4] = data_to_bcd(day); // day 58 | buffer[5] = data_to_bcd(date); // date 59 | buffer[6] = data_to_bcd(month); // month 60 | buffer[7] = data_to_bcd(year); // year 61 | buffer[8] = 0; // control 62 | 63 | I2C_InitializeIfNot(I2C_BAUD_RATE_100KHZ, I2C_ENABLE_INTERRUPTS); 64 | 65 | return I2C_BulkWrite(buffer, 9, DS1307_I2C_DEVICE_ADDRESS); 66 | } 67 | 68 | response_t RTC_CmdSetTime(void) { 69 | uint32_t unix_timestamp = UART1_read_u32(); 70 | 71 | response_t res = RTC_SetTime(&unix_timestamp); 72 | return res; 73 | } 74 | 75 | response_t RTC_SetDigit(void) { 76 | 77 | uint8_t buffer[2]; 78 | buffer[0] = UART1_Read(); // register address 79 | buffer[1] = UART1_Read(); // data 80 | 81 | I2C_InitializeIfNot(I2C_BAUD_RATE_100KHZ, I2C_ENABLE_INTERRUPTS); 82 | 83 | return I2C_BulkWrite(buffer, 2, DS1307_I2C_DEVICE_ADDRESS); 84 | } 85 | 86 | response_t RTC_GetTime(uint32_t* unix_timestamp) { 87 | 88 | uint8_t buffer[7]; 89 | struct tm tm_info; 90 | 91 | I2C_InitializeIfNot(I2C_BAUD_RATE_100KHZ, I2C_ENABLE_INTERRUPTS); 92 | 93 | if(I2C_BulkRead(DS1307_DATA_REG_SECONDS, DS1307_I2C_DEVICE_ADDRESS, buffer, 7) == SUCCESS) { 94 | 95 | // Need to convert from bcd to int. 96 | tm_info.tm_sec = bcd_to_data(buffer[0]); 97 | tm_info.tm_min = bcd_to_data(buffer[1]); 98 | tm_info.tm_hour = bcd_to_data(buffer[2]); 99 | tm_info.tm_wday = bcd_to_data(buffer[3]) - 1; 100 | tm_info.tm_mday = bcd_to_data(buffer[4]); 101 | tm_info.tm_mon = bcd_to_data(buffer[5]) - 1; 102 | tm_info.tm_year = 100 + bcd_to_data(buffer[6]); // 100 means for year 2000 (2000 - 1900) 103 | 104 | tm_info.tm_sec = tm_info.tm_sec & oscillator_enable; 105 | 106 | uint32_t timestamp = (uint32_t) mktime(&tm_info); 107 | *unix_timestamp = timestamp; 108 | } else return FAILED; 109 | 110 | return SUCCESS; 111 | } 112 | 113 | response_t RTC_CmdGetTime(void){ 114 | uint32_t unix_timestamp; 115 | response_t res = RTC_GetTime(&unix_timestamp); 116 | 117 | // What if error occurs here, Returns fail. 118 | UART1_write_u32(unix_timestamp); 119 | return res; 120 | } 121 | 122 | response_t RTC_GetDigit(void) { 123 | 124 | uint8_t buffer[1]; 125 | uint8_t reg = UART1_Read(); // register address 126 | uint8_t *pR = ® 127 | 128 | I2C_InitializeIfNot(I2C_BAUD_RATE_100KHZ, I2C_ENABLE_INTERRUPTS); 129 | 130 | if(I2C_BulkRead(pR, DS1307_I2C_DEVICE_ADDRESS, buffer, 1) == SUCCESS) { 131 | UART1_Write(buffer[0]); 132 | } else return FAILED; 133 | 134 | return SUCCESS; 135 | } 136 | -------------------------------------------------------------------------------- /src/instruments/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(pslab-firmware.elf PRIVATE 2 | logicanalyzer.c 3 | multimeter.c 4 | oscilloscope.c 5 | powersource.c 6 | sensors.c 7 | wavegenerator.c 8 | ) 9 | 10 | target_include_directories(pslab-firmware.elf 11 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 12 | 13 | -------------------------------------------------------------------------------- /src/instruments/multimeter.h: -------------------------------------------------------------------------------- 1 | #ifndef MULTIMETER_H 2 | #define MULTIMETER_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /** 9 | * @brief Read a single voltage instance using ADC 10 | * @return SUCCESS 11 | */ 12 | response_t MULTIMETER_GetVoltage(void); 13 | 14 | /** 15 | * @brief Read multiple (16) voltage instances using ADC 16 | * @return SUCCESS 17 | */ 18 | response_t MULTIMETER_GetVoltageSummed(void); 19 | 20 | /** 21 | * @brief Charge or discharge capacitor through a resistor 22 | * @return SUCCESS 23 | */ 24 | response_t MULTIMETER_ChargeCapacitor(void); 25 | 26 | /** 27 | * @brief Use CTMU to measure capacitance value and read it 28 | * @return SUCCESS 29 | */ 30 | response_t MULTIMETER_GetCapacitance(void); 31 | 32 | /** 33 | * @brief Get an estimate of the capacitor range 34 | * 35 | * @description 36 | * This function can be used to get an estimate of how large a 37 | * capacitor is. One use case could be to compare two different 38 | * capacitors without having to evaluate the exact capacitance. 39 | * This command takes only one argument over serial: 40 | * 1. (uint16) Charge time in micro seconds 41 | * 42 | * It returns the range value as uint16. 43 | * 44 | * @return SUCCESS 45 | */ 46 | response_t MULTIMETER_GetCapRange(void); 47 | 48 | /** 49 | * @brief Measurements using Charge Time Measurement Unit 50 | * 51 | * @description 52 | * This command function takes one argument over serial: 53 | * 1. (uint8) Configuration byte: 54 | * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 55 | * | DG | CSO | CHANNEL | 56 | * DG: Delay generator enable/disable (1/0) 57 | * CSO: Current source output: 58 | * 00: Base * 1000 59 | * 01: Base = 0.53 uA 60 | * 10: Base * 10 61 | * 11: Base * 100 62 | * CHANNEL: CTMU channel 63 | * 64 | * It returns nothing over serial. 65 | * It sends an acknowledge byte (SUCCESS). This will be available only after 66 | * no less than 2.5 milliseconds. 67 | * 68 | * @return SUCCESS 69 | */ 70 | response_t MULTIMETER_GetCTMUVolts(void); 71 | 72 | #ifdef __cplusplus 73 | } 74 | #endif 75 | 76 | #endif /* MULTIMETER_H */ 77 | -------------------------------------------------------------------------------- /src/instruments/oscilloscope.h: -------------------------------------------------------------------------------- 1 | #ifndef OSCILLOSCOPE_H 2 | #define OSCILLOSCOPE_H 3 | 4 | /** 5 | * @brief Capture samples on a single channel. 6 | * 7 | * @description 8 | * This command function takes three arguments over serial: 9 | * 1. (uint8) Configuration byte: 10 | * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 11 | * | TE | - | - | CH123SA | CH0SA | 12 | * TE: Trigger enable 13 | * CH123SA: Second, third, and fourth channels input map: 14 | * 0: CH2, CH3, MIC 15 | * 1: CH1, CH2, CAP 16 | * CH0SA: First channel input map: 17 | * 3: CH1, 18 | * 0: CH2, 19 | * 1: CH3, 20 | * 2: MIC, 21 | * 7: RES, 22 | * 5: CAP, 23 | * 8: VOL, 24 | * 2. (uint16) The number of samples to capture. 25 | * 3. (uint16) The time to wait between samples in instruction cycles. 26 | * It returns nothing over serial. 27 | * It sends an acknowledge byte (SUCCESS). 28 | * 29 | * @return SUCCESS 30 | */ 31 | response_t OSCILLOSCOPE_CaptureOne(void); 32 | 33 | /** 34 | * @brief Capture samples on two channels simultaneously. 35 | */ 36 | response_t OSCILLOSCOPE_CaptureTwo(void); 37 | 38 | /** 39 | * @brief Capture samples on three channels simultaneously. 40 | * 41 | * @description 42 | * Since the MCU only supports 1, 2, or 4 simultaneous channels, this is 43 | * accomplished by sampling four channels simultaneously and discarding the 44 | * samples from the fourth. This function therefore has the same sample rate 45 | * as OSCILLOSCOPE_CaptureFour, but greater sample depth. 46 | */ 47 | response_t OSCILLOSCOPE_CaptureThree(void); 48 | 49 | /** 50 | * @brief Capture samples on four channels simultaneously. 51 | */ 52 | response_t OSCILLOSCOPE_CaptureFour(void); 53 | 54 | /** 55 | * @brief Capture samples on one channel as fast as possible. 56 | * 57 | * @description 58 | * Direct memory access moves samples from ADC to RAM buffer as soon as 59 | * conversion is complete. Allows for faster sample rate than using ADC 60 | * interrupt, at the cost of only supporting a single channel and no trigger. 61 | * This command function takes three arguments over serial: 62 | * 1. (uint8) Configuration byte: 63 | * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 64 | * | RES | - | - | - | CH0SA | 65 | * RES: Sample resolution: 66 | * 0: 10-bit, 67 | * 1: 12-bit, 68 | * CH0SA: First channel input map: 69 | * 3: CH1, 70 | * 0: CH2, 71 | * 1: CH3, 72 | * 2: MIC, 73 | * 7: RES, 74 | * 5: CAP, 75 | * 8: VOL, 76 | * 2. (uint16) The number of samples to capture. 77 | * 3. (uint16) The time to wait between samples in instruction cycles. 78 | * It returns nothing over serial. 79 | * It sends an acknowledge byte (SUCCESS). 80 | */ 81 | response_t OSCILLOSCOPE_CaptureDMA(void); 82 | 83 | /** 84 | * @brief 85 | * Send capture progress. 86 | * 87 | * @description 88 | * This command function takes no arguments over serial. 89 | * It returns two values over serial: 90 | * 1. (bool) True if all requested samples have been captured. 91 | * 2. (uint16) Number of captured samples. 92 | * It sends an acknowledge byte (SUCCESS). 93 | * 94 | * @return SUCCESS 95 | */ 96 | response_t OSCILLOSCOPE_GetCaptureStatus(void); 97 | 98 | /** 99 | * @brief 100 | * Select trigger channel and trigger level. 101 | * 102 | * @description 103 | * This command function takes two arguments over serial. 104 | * 1. (uint8) Configuration byte: 105 | * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 106 | * | Prescaler | CHSEL | 107 | * Prescaler: The trigger times out (i.e. capture starts) after: 108 | * timeout = DELAY * (50000 / (DELAY >> prescaler)) / 8 us 109 | * If DELAY >> prescaler == 0 trigger does not time out. 110 | * CHSEL: Trigger channel select. 111 | * b0000: Disable trigger, 112 | * b0001: Trigger on CH0SA, 113 | * b0010: Trigger on CH123SA[0], 114 | * b0100: Trigger on CH123SA[1], 115 | * b1000. Trigger on CH123SA[2], 116 | * It is not necessary to sample the trigger channel, but 117 | * the trigger channel must still be converted which affects 118 | * the sample rate. 119 | * 2. (uint16) Trigger voltage. 120 | * It returns nothing over serial. 121 | * 122 | * @return SUCCESS 123 | */ 124 | response_t OSCILLOSCOPE_ConfigureTrigger(void); 125 | 126 | /** 127 | * @brief Set gain on CH1 or CH2. 128 | * @param channel uint8_t 129 | * 1: CH1 130 | * 2: CH2 131 | * @param gain uint8_t 132 | * 0: 1 133 | * 1: 2 134 | * 2: 4 135 | * 3: 5 136 | * 4: 8 137 | * 5: 10 138 | * 6: 16 139 | * 7: 32 140 | * 141 | * @return FAILED if channel is not 1 or 2. 142 | * FAILED if gain is greater than 7. 143 | * FAILED if SPI transaction fails. 144 | * SUCCESS otherwise. 145 | */ 146 | response_t OSCILLOSCOPE_SetPGAGain(void); 147 | 148 | #endif /* OSCILLOSCOPE_H */ 149 | -------------------------------------------------------------------------------- /src/instruments/powersource.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../commands.h" 3 | #include "../bus/uart/uart.h" 4 | #include "../bus/i2c/i2c.h" 5 | #include "../bus/spi/spi.h" 6 | #include "powersource.h" 7 | 8 | /*********/ 9 | /* Types */ 10 | /*********/ 11 | 12 | /** @brief Channel selection. 13 | * @details 14 | * V5 hardware has four independent channels: 15 | * 0: PCS 16 | * 1: PV3 17 | * 2: PV2 18 | * 3: PV1 19 | * V6 hardware has two pairs of paired channels: 20 | * 0: PCS & PVS2 21 | * 1: PVS1 & PVS3 22 | * Paired channels share relative output levels, i.e. if PV1 outputs 5 V 23 | * then PV3 outputs 3.3 V. 24 | */ 25 | enum Channel { 26 | PCS, 27 | PV3, 28 | PV2, 29 | PV1, 30 | NUM_V5_CHANNELS, 31 | PVS2_PCS = 0, 32 | PVS1_PVS3, 33 | NUM_V6_CHANNELS, 34 | }; 35 | 36 | /** @brief Output gain selection bit. 37 | * @details 38 | * The gain values are reversed between the MCP4822 (v6) and the 39 | * MCP4728 (v5). Thanks, Microchip! 40 | */ 41 | enum Gain { 42 | #ifndef V5_HW 43 | GAIN_X2, 44 | GAIN_X1, 45 | #else 46 | GAIN_X1, 47 | GAIN_X2, 48 | #endif // V5_HW 49 | GAINS 50 | }; 51 | int GAINVAL[GAINS] = {[GAIN_X1] = 1, [GAIN_X2] = 2}; 52 | 53 | #ifndef V5_HW 54 | 55 | /// @brief Output shutdown control bit. 56 | enum Output { 57 | OUTPUT_OFF, 58 | OUTPUT_ON 59 | }; 60 | 61 | /// @brief MCP4822 write command, 4 configuration bits + 12 data bits. 62 | union MCP4822Command { 63 | struct { 64 | uint16_t DATA : 12; 65 | uint16_t SHDN : 1; 66 | uint16_t GA : 1; 67 | uint16_t : 1; 68 | uint16_t AB : 1; 69 | }; 70 | uint16_t reg; 71 | }; 72 | 73 | #else // V5_HW 74 | 75 | /** @brief Output shutdown control bit. 76 | * @details 77 | * Also reversed compared to MCP4822. When not on, DAC output is pulled to 78 | * ground via a 1K, 100K, or 500K resistor. 79 | */ 80 | enum Output { 81 | OUTPUT_ON, 82 | OUTPUT_OFF_1K, 83 | OUTPUT_OFF_100K, 84 | OUTPUT_OFF, // 500K 85 | }; 86 | 87 | union MCP4728Command { 88 | struct { 89 | uint16_t : 1; // UDAC 90 | uint16_t DAC : 2; 91 | uint16_t CMD : 5; 92 | 93 | uint16_t DATA_H : 4; 94 | uint16_t GX : 1; 95 | uint16_t PDSEL : 2; 96 | uint16_t VREF : 1; 97 | 98 | uint16_t DATA_L : 8; 99 | }; 100 | uint8_t buffer[3]; 101 | }; 102 | 103 | #endif // V5_HW 104 | 105 | /********************/ 106 | /* Static functions */ 107 | /********************/ 108 | 109 | #ifndef V5_HW 110 | 111 | static bool initialize(void) 112 | { 113 | const SPI_Config conf = {{{ 114 | .PPRE = SPI_SCLK125000 >> 3, 115 | .SPRE = SPI_SCLK125000 & 7, 116 | .MSTEN = 1, 117 | .CKP = SPI_IDLE_LOW, 118 | .SSEN = 0, 119 | .CKE = SPI_SHIFT_TRAILING, 120 | .SMP = 1, 121 | .MODE16 = 1, 122 | .DISSDO = 0, 123 | .DISSCK = 0 124 | }}}; 125 | return SPI_configure(conf); 126 | } 127 | 128 | /** 129 | * @brief Convert a V5 pin number to the corresponding pin number for the V6. 130 | * @details See documentation for Channel. 131 | * @param channel 132 | * @return enum Channel 133 | */ 134 | static enum Channel v5_to_v6_channel(enum Channel const channel) 135 | { 136 | return (channel + 1) % 2; 137 | } 138 | 139 | /************************/ 140 | /* Command functions */ 141 | /************************/ 142 | 143 | response_t POWER_SOURCE_SetPower(void) 144 | { 145 | enum Channel const channel = v5_to_v6_channel(UART1_Read() & 0x03); 146 | uint16_t const output = UART1_ReadInt() & 0xFFF; 147 | union MCP4822Command cmd = {{ 148 | .DATA = output, 149 | .SHDN = OUTPUT_ON, 150 | .GA = GAIN_X2, 151 | .AB = channel, 152 | }}; 153 | 154 | if(initialize()) { 155 | return ( 156 | SPI_exchange_int(SPI_PS, &cmd.reg) ? SUCCESS : FAILED 157 | ); 158 | } 159 | return FAILED; 160 | } 161 | 162 | #else // V5_HW 163 | 164 | response_t POWER_SOURCE_SetPower(void) { 165 | enum VRef { 166 | VREF_EXTERNAL, 167 | VREF_INTERNAL, 168 | }; 169 | enum Command { 170 | SINGLE_WRITE = 0b01011, 171 | }; 172 | uint8_t const channel = UART1_Read() & 0x03; 173 | uint16_t const output = UART1_ReadInt() & 0xFFF; 174 | union MCP4728Command cmd = {{ 175 | .CMD = SINGLE_WRITE, 176 | .DAC = channel, 177 | .VREF = VREF_INTERNAL, 178 | .PDSEL = OUTPUT_ON, 179 | .GX = GAIN_X2, 180 | .DATA_L = output & 0xFF, 181 | .DATA_H = output >> 8 182 | }}; 183 | I2C_InitializeIfNot(I2C_BAUD_RATE_400KHZ, I2C_ENABLE_INTERRUPTS); 184 | 185 | enum MCP4728Address { 186 | ADDRESS = 0x60, 187 | }; 188 | 189 | return I2C_BulkWrite( 190 | cmd.buffer, 191 | sizeof(cmd.buffer), 192 | ADDRESS 193 | ); 194 | } 195 | 196 | #endif // V5_HW 197 | -------------------------------------------------------------------------------- /src/instruments/powersource.h: -------------------------------------------------------------------------------- 1 | #ifndef POWER_SOURCE_H 2 | #define POWER_SOURCE_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif /* __cplusplus */ 7 | 8 | /** 9 | * @brief Set the voltage output of the power source's individual channels. 10 | * 11 | * @param channel uint8_t 12 | * One of the DAC channels: 13 | * PSLab V6: 14 | * 0 (0b00) - PCS & PVS2 15 | * 1 (0b01) - PVS1 & PVS3 16 | * PSLab V5: 17 | * 0 (0b00) - PCS 18 | * 1 (0b01) - PV3 19 | * 2 (0b10) - PV2 20 | * 3 (0b11) - PV1 21 | * @param output uint16 22 | * Channel output level in mV relative to the VDD line (3300 mV). A 23 | * value of 0 produces an output equal to the low end of the channel's 24 | * range; a value of 3300 produces an output equal to the high end of 25 | * the channel's range: 26 | * channel output==0 output==3300 27 | * PV(S)1 -5 V 5 V 28 | * PV(S)2 -3.3 V 3.3 V 29 | * PV(S)3 0 V 3.3 V 30 | * PCS 3.3 mA 0 A 31 | * Note that the direction of the output range for the PCS channel is 32 | * inverted compared to the other channels. 33 | * 34 | * @return SUCCESS, FAILED 35 | */ 36 | response_t POWER_SOURCE_SetPower(void); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | 42 | #endif /* POWER_SOURCE_H */ 43 | -------------------------------------------------------------------------------- /src/instruments/sensors.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * This file contains secondary measurements and configurations used by other 3 | * instruments 4 | ******************************************************************************/ 5 | 6 | #include "../registers/comparators/cmp4.h" 7 | #include "../registers/comparators/cvr.h" 8 | #include "../registers/comparators/ic1.h" 9 | #include "../registers/comparators/ic2.h" 10 | #include "../registers/comparators/ic3.h" 11 | #include "../registers/comparators/ic4.h" 12 | #include "../bus/uart/uart.h" 13 | #include "../registers/timers/tmr2.h" 14 | #include "../registers/system/pin_manager.h" 15 | 16 | void SENSORS_ConfigureInterval(uint8_t pin1, uint8_t pin2, 17 | IC_PARAMS_CAPTURE_MODE pin1_edge, IC_PARAMS_CAPTURE_MODE pin2_edge) { 18 | 19 | // Map pin1 as IC1 source pin 20 | RPINR7bits.IC1R = PIN_MANAGER_DIGITAL_PINS[pin1]; 21 | // Map pin2 as IC3 source pin 22 | RPINR8bits.IC3R = PIN_MANAGER_DIGITAL_PINS[pin2]; 23 | 24 | IC1_Initialize(); 25 | IC2_Initialize(); 26 | IC3_Initialize(); 27 | IC4_Initialize(); 28 | 29 | IC1_SetCaptureTimer(IC_PARAMS_CAPTURE_TIMER_PERIPHERAL); 30 | IC2_SetCaptureTimer(IC_PARAMS_CAPTURE_TIMER_PERIPHERAL); 31 | IC3_SetCaptureTimer(IC_PARAMS_CAPTURE_TIMER_PERIPHERAL); 32 | IC4_SetCaptureTimer(IC_PARAMS_CAPTURE_TIMER_PERIPHERAL); 33 | 34 | // Combine IC1 and IC2 modules to capture one type of edge 35 | IC1_CombineOddEvenICModules(); 36 | IC2_CombineOddEvenICModules(); 37 | // Combine IC3 and IC4 modules to capture another type of edge 38 | IC3_CombineOddEvenICModules(); 39 | IC4_CombineOddEvenICModules(); 40 | 41 | IC1_InterruptFlagClear(); 42 | IC3_InterruptFlagClear(); 43 | 44 | IC1_SetCaptureMode(pin1_edge); 45 | IC2_SetCaptureMode(pin1_edge); 46 | IC3_SetCaptureMode(pin2_edge); 47 | IC4_SetCaptureMode(pin2_edge); 48 | 49 | IC1_ManualTriggerSet(); 50 | IC2_ManualTriggerSet(); 51 | IC3_ManualTriggerSet(); 52 | IC4_ManualTriggerSet(); 53 | } 54 | 55 | response_t SENSORS_StartCounter(void) { 56 | 57 | uint8_t channel = UART1_Read(); 58 | 59 | TMR2_Initialize(); 60 | // Select external source as clock source 61 | T2CONbits.TCS = 1; 62 | 63 | if (channel == 4) { 64 | CVR_SetupComparator(); 65 | CMP4_SetupComparator(); 66 | } 67 | 68 | // Map incoming pin to TMR2 69 | RPINR3bits.T2CKR = PIN_MANAGER_DIGITAL_PINS[channel]; 70 | TMR2_Start(); 71 | 72 | return SUCCESS; 73 | } 74 | 75 | response_t SENSORS_GetCounter(void) { 76 | // Fetch timer 2 value and send it over 77 | UART1_WriteInt(TMR2_Counter16BitGet()); 78 | return SUCCESS; 79 | } -------------------------------------------------------------------------------- /src/instruments/sensors.h: -------------------------------------------------------------------------------- 1 | #ifndef SENSORS_H 2 | #define SENSORS_H 3 | 4 | #include 5 | #include "../registers/comparators/ic_params.h" 6 | 7 | /** 8 | * @brief This method will configure all 4 Input Capture modules to listen 9 | * to state changes in pin1 and pin2. The state changes are defined in 10 | * IC_PARAMS_CAPTURE_MODE and each of the pin is fetched from the array 11 | * PIN_MANAGER_DIGITAL_PINS. Once this function is called, the timer values 12 | * correspond to each state change on each pin will be stored in the Input 13 | * Capture timer registers. These timer values need to be fetched by the 14 | * user using a different routine. 15 | * 16 | * @param pin1 First pin connected to a Digital pin 17 | * @param pin2 Second pin connected to a Digital pin 18 | * @param pin1_edge Triggering transition on pin 1 19 | * @param pin2_edge Triggering transition on pin 2 20 | * 21 | * @return None 22 | */ 23 | void SENSORS_ConfigureInterval(uint8_t pin1, uint8_t pin2, 24 | IC_PARAMS_CAPTURE_MODE pin1_edge, IC_PARAMS_CAPTURE_MODE pin2_edge); 25 | 26 | /** 27 | * @brief This method will implement a counter using logic level variations 28 | * of a digital pin. 29 | * 30 | * @description 31 | * This command takes one argument over serial 32 | * 1. (uint8) digital pin 33 | * This pin has to be one of the pins from PIN_MANAGER_DIGITAL_PINS array 34 | * 35 | * It returns nothing over serial. 36 | * 37 | * One of the use cases of this method could be when counting a set of 38 | * pebbles. One can connect a light encoder output pin to the pin specified 39 | * as the `digital pin` and by passing the pebbles through the encoder will 40 | * keep on incrementing a counter. This value can be fetched from routine 41 | * SENSORS_GetCounter(); 42 | * 43 | * @return SUCCESS 44 | */ 45 | response_t SENSORS_StartCounter(void); 46 | 47 | /** 48 | * @brief Fetch the counter value in TMR2 register 49 | * 50 | * @description 51 | * This method does not take any arguments over serial. It will return the 52 | * value stored in timer 2 counting register. This value is most likely 53 | * captured from SENSORS_StartCounter method 54 | * 55 | * @return SUCCESS 56 | */ 57 | response_t SENSORS_GetCounter(void); 58 | 59 | #endif /* SENSORS_H */ 60 | 61 | -------------------------------------------------------------------------------- /src/instruments/wavegenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef WAVEGENERATOR_H 2 | #define WAVEGENERATOR_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /** 9 | * @brief Replace default wave table pattern 1 with a user defined sequence 10 | * @return SUCCESS 11 | */ 12 | response_t WAVEGENERATOR_LoadWaveForm1(void); 13 | 14 | /** 15 | * @brief Reads the content of wave table pattern 1 16 | * @return SUCCESS 17 | */ 18 | response_t WAVEGENERATOR_ReadWaveForm1(void); 19 | 20 | /** 21 | * @brief Replace default wave table pattern 2 with a user defined sequence 22 | * @return SUCCESS 23 | */ 24 | response_t WAVEGENERATOR_LoadWaveForm2(void); 25 | 26 | /** 27 | * @brief Reads the content of wave table pattern 2 28 | * @return SUCCESS 29 | */ 30 | response_t WAVEGENERATOR_ReadWaveForm2(void); 31 | 32 | /** 33 | * @brief Generate sine wave from SIN1 pin 34 | * @return SUCCESS 35 | */ 36 | response_t WAVEGENERATOR_SetSine1(void); 37 | 38 | /** 39 | * @brief Generate sine wave from SIN2 pin 40 | * @return SUCCESS 41 | */ 42 | response_t WAVEGENERATOR_SetSine2(void); 43 | 44 | /** 45 | * @brief Generate two sine waves from SIN1 and SIN2 pins 46 | * @return SUCCESS 47 | */ 48 | response_t WAVEGENERATOR_SetSineDual(void); 49 | 50 | /** 51 | * @brief Generate PWM wave from SQR1 pin 52 | * @return SUCCESS 53 | */ 54 | response_t WAVEGENERATOR_SetSquare1(void); 55 | 56 | /** 57 | * @brief Generate PWM wave from SQR2 pin 58 | * @return SUCCESS 59 | */ 60 | response_t WAVEGENERATOR_SetSquare2(void); 61 | 62 | /** 63 | * @brief Generate PWM wave from all SQR pins 64 | * @return SUCCESS 65 | */ 66 | response_t WAVEGENERATOR_SetSquareAll(void); 67 | 68 | /** 69 | * @brief Link system oscillator to an output pin 70 | * @return SUCCESS 71 | */ 72 | response_t WAVEGENERATOR_MapReference(void); 73 | 74 | #ifdef __cplusplus 75 | } 76 | #endif 77 | 78 | #endif /* WAVEGENERATOR_H */ 79 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include "registers/system/system.h" 2 | #include "states.h" 3 | 4 | int main(void) { 5 | 6 | SYSTEM_Initialize(); 7 | 8 | state_t current_state = STATE_STANDBY; 9 | 10 | while (1) { 11 | current_state = STATES_RunState(current_state); 12 | } 13 | 14 | return 1; 15 | } 16 | -------------------------------------------------------------------------------- /src/registers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(comparators) 2 | add_subdirectory(converters) 3 | add_subdirectory(memory) 4 | add_subdirectory(system) 5 | add_subdirectory(timers) 6 | -------------------------------------------------------------------------------- /src/registers/comparators/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(pslab-firmware.elf PRIVATE 2 | cmp_params.c 3 | cmp1.c 4 | cmp2.c 5 | cmp3.c 6 | cmp4.c 7 | cvr.c 8 | ic_params.c 9 | ic1.c 10 | ic2.c 11 | ic3.c 12 | ic4.c 13 | oc1.c 14 | oc2.c 15 | oc3.c 16 | oc4.c 17 | ) 18 | 19 | target_include_directories(pslab-firmware.elf 20 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 21 | 22 | -------------------------------------------------------------------------------- /src/registers/comparators/cmp1.c: -------------------------------------------------------------------------------- 1 | #include "cmp1.h" 2 | 3 | void CMP1_Initialize(void) { 4 | // PSIDL disabled; 5 | CMSTAT = 0x00; 6 | // CON enabled; CPOL Not Inverted; OPMODE Comparator; EVPOL Disabled; COE disabled; CCH C1IN1-; CREF C1IN1+; CEVT disabled; 7 | CM1CON = 0x8000 & ~(0x8000); //disabling Comparator CON bit 8 | // SELSRCC PWM1L; SELSRCB PWM1L; SELSRCA PWM1L; 9 | CM1MSKSRC = 0x00; 10 | // AANEN disabled; ABNEN disabled; ACNEN disabled; HLMS disabled; OANEN disabled; ABEN disabled; ACEN disabled; AAEN disabled; PAGS disabled; OBEN disabled; OCEN disabled; NAGS disabled; OCNEN disabled; OBNEN disabled; OAEN disabled; 11 | CM1MSKCON = 0x00; 12 | // CFSEL FOSC/2; CFLTREN disabled; CFDIV 1:1; 13 | CM1FLTR = 0x00; 14 | 15 | CM1CONbits.CON = 1; //enabling Comparator CON bit 16 | } 17 | 18 | bool CMP1_OutputStatusGet(void) { 19 | return (CM1CONbits.COUT); 20 | } 21 | 22 | bool CMP1_EventStatusGet(void) { 23 | return (CM1CONbits.CEVT); 24 | } 25 | 26 | void CMP1_EventStatusReset(void) { 27 | CM1CONbits.CEVT = 0; 28 | } 29 | 30 | bool CMP1_HLMSStatusGet(void) { 31 | return (CM1MSKCONbits.HLMS); 32 | } 33 | 34 | void CMP1_ComparatorDisable(void) { 35 | CM1CONbits.CON = 0; 36 | } 37 | 38 | void CMP1_ComparatorEnable(void) { 39 | CM1CONbits.CON = 1; 40 | } 41 | 42 | void __attribute__((weak)) CMP1_CallBack(void) { 43 | // Add your custom callback code here 44 | } 45 | 46 | void CMP1_Tasks(void) { 47 | if (IFS1bits.CMIF) { 48 | // CMP1 callback function 49 | CMP1_CallBack(); 50 | 51 | // Clear the CEVT bit to enable further interrupts 52 | CMP1_EventStatusReset(); 53 | 54 | // clear the CMP1 interrupt flag 55 | IFS1bits.CMIF = 0; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/registers/comparators/cmp1.h: -------------------------------------------------------------------------------- 1 | #ifndef _CMP1_H 2 | #define _CMP1_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef __cplusplus // Provide C++ Compatibility 10 | extern "C" { 11 | #endif 12 | 13 | /** 14 | @Summary 15 | This function initializes Comparator instance : 1 16 | 17 | @Description 18 | This routine initializes the Comparator driver instance for : 1, 19 | making it ready for clients to open and use it. It also initializes any 20 | internal data structures. 21 | 22 | @Param 23 | None. 24 | 25 | @Returns 26 | None 27 | 28 | @Comment 29 | 30 | */ 31 | void CMP1_Initialize(void); 32 | /** 33 | void CMP1_Initialize(void) 34 | */ 35 | 36 | /** 37 | @Summary 38 | This function returns the output of the comparator 39 | 40 | @Description 41 | This routine returns the output of the comparator. It returns a bool which 42 | is the output of the comparator. 43 | 44 | @Param 45 | None. 46 | 47 | @Returns 48 | None 49 | 50 | */ 51 | bool CMP1_OutputStatusGet(void); 52 | /** 53 | bool CMP1_OutputStatusGet(void) 54 | */ 55 | 56 | /** 57 | @Summary 58 | This function returns the if the comparator event has occurred or not 59 | 60 | @Description 61 | This routine returns true if the comparator event has occurred. It returns false 62 | if the comparator event has not occurred yet. 63 | 64 | @Param 65 | None. 66 | 67 | @Returns 68 | bool. 69 | 70 | */ 71 | bool CMP1_EventStatusGet(void); 72 | /** 73 | bool CMP1_EventStatusGet(void) 74 | */ 75 | 76 | /** 77 | @Summary 78 | This function resets the event status bit of the comparator. 79 | 80 | @Description 81 | This routine resets the event status bit of the comparator after the comparator 82 | event has occurred. 83 | 84 | @Param 85 | None. 86 | 87 | @Returns 88 | bool. 89 | 90 | */ 91 | void CMP1_EventStatusReset(void); 92 | /** 93 | void CMP1_EventStatusReset(void) 94 | */ 95 | /** 96 | @Summary 97 | This function get the status of the HLMS bit of the blanking function of the comparator. 98 | 99 | @Description 100 | This routine will prevent any asserted ('0' or '1') comparator signal from propagating 101 | 102 | @Param 103 | None. 104 | 105 | @Returns 106 | bool. 107 | */ 108 | void CMP1_ComparatorDisable(void); 109 | /** 110 | void CMP1_ComparatorDisable(void) 111 | */ 112 | /** 113 | @Summary 114 | Disables the comparator module. 115 | 116 | @Description 117 | This routine disables the comparator module. 118 | 119 | @Param 120 | None. 121 | 122 | @Returns 123 | bool. 124 | */ 125 | void CMP1_ComparatorEnable(void); 126 | /** 127 | void CMP1_ComparatorEnable(void) 128 | */ 129 | /** 130 | @Summary 131 | Enables the comparator module. 132 | 133 | @Description 134 | This routine enables the comparator module.. 135 | 136 | @Param 137 | None. 138 | 139 | @Returns 140 | bool. 141 | */ 142 | bool CMP1_HLMSStatusGet(void); 143 | /** 144 | bool CMP1_HLMSStatusGet(void) 145 | */ 146 | 147 | /** 148 | @Summary 149 | Callback for CMP1. 150 | 151 | @Description 152 | This routine is callback for CMP1 153 | 154 | @Param 155 | None. 156 | 157 | @Returns 158 | None 159 | 160 | @Example 161 | Refer to CMP1_Initialize(); for an example 162 | */ 163 | void CMP1_CallBack(void); 164 | 165 | /** 166 | @Summary 167 | Polled implementation 168 | 169 | @Description 170 | This routine is used to implement the tasks for polled implementations. 171 | 172 | @Preconditions 173 | CMP1_Initialize() function should have been 174 | called before calling this function. 175 | 176 | @Returns 177 | None 178 | 179 | @Param 180 | None 181 | 182 | @Example 183 | Refer to CMP1_Initialize(); for an example 184 | 185 | */ 186 | void CMP1_Tasks(void); 187 | 188 | #ifdef __cplusplus // Provide C++ Compatibility 189 | } 190 | #endif 191 | 192 | #endif //_CMP1_H 193 | -------------------------------------------------------------------------------- /src/registers/comparators/cmp2.c: -------------------------------------------------------------------------------- 1 | #include "cmp2.h" 2 | 3 | void CMP2_Initialize(void) { 4 | // PSIDL disabled; 5 | CMSTAT = 0x00; 6 | // CON enabled; CPOL Not Inverted; OPMODE Comparator; EVPOL Disabled; COE disabled; CCH C2IN1-; CREF C2IN1+; CEVT disabled; 7 | CM2CON = 0x8000 & ~(0x8000); //disabling Comparator CON bit 8 | // SELSRCC PWM1L; SELSRCB PWM1L; SELSRCA PWM1L; 9 | CM2MSKSRC = 0x00; 10 | // AANEN disabled; ABNEN disabled; ACNEN disabled; HLMS disabled; OANEN disabled; ABEN disabled; ACEN disabled; AAEN disabled; PAGS disabled; OBEN disabled; OCEN disabled; NAGS disabled; OCNEN disabled; OBNEN disabled; OAEN disabled; 11 | CM2MSKCON = 0x00; 12 | // CFSEL FOSC/2; CFLTREN disabled; CFDIV 1:1; 13 | CM2FLTR = 0x00; 14 | 15 | CM2CONbits.CON = 1; //enabling Comparator CON bit 16 | } 17 | 18 | bool CMP2_OutputStatusGet(void) { 19 | return (CM2CONbits.COUT); 20 | } 21 | 22 | bool CMP2_EventStatusGet(void) { 23 | return (CM2CONbits.CEVT); 24 | } 25 | 26 | void CMP2_EventStatusReset(void) { 27 | CM2CONbits.CEVT = 0; 28 | } 29 | 30 | bool CMP2_HLMSStatusGet(void) { 31 | return (CM2MSKCONbits.HLMS); 32 | } 33 | 34 | void CMP2_ComparatorDisable(void) { 35 | CM2CONbits.CON = 0; 36 | } 37 | 38 | void CMP2_ComparatorEnable(void) { 39 | CM2CONbits.CON = 1; 40 | } 41 | 42 | void __attribute__((weak)) CMP2_CallBack(void) { 43 | // Add your custom callback code here 44 | } 45 | 46 | void CMP2_Tasks(void) { 47 | if (IFS1bits.CMIF) { 48 | // CMP2 callback function 49 | CMP2_CallBack(); 50 | 51 | // Clear the CEVT bit to enable further interrupts 52 | CMP2_EventStatusReset(); 53 | 54 | // clear the CMP2 interrupt flag 55 | IFS1bits.CMIF = 0; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/registers/comparators/cmp2.h: -------------------------------------------------------------------------------- 1 | #ifndef _CMP2_H 2 | #define _CMP2_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef __cplusplus // Provide C++ Compatibility 10 | extern "C" { 11 | #endif 12 | 13 | /** 14 | @Summary 15 | This function initializes Comparator instance : 2 16 | 17 | @Description 18 | This routine initializes the Comparator driver instance for : 2, 19 | making it ready for clients to open and use it. It also initializes any 20 | internal data structures. 21 | 22 | @Param 23 | None. 24 | 25 | @Returns 26 | None 27 | 28 | @Comment 29 | 30 | */ 31 | void CMP2_Initialize(void); 32 | /** 33 | void CMP2_Initialize(void) 34 | */ 35 | 36 | /** 37 | @Summary 38 | This function returns the output of the comparator 39 | 40 | @Description 41 | This routine returns the output of the comparator. It returns a bool which 42 | is the output of the comparator. 43 | 44 | @Param 45 | None. 46 | 47 | @Returns 48 | None 49 | 50 | */ 51 | bool CMP2_OutputStatusGet(void); 52 | /** 53 | bool CMP2_OutputStatusGet(void) 54 | */ 55 | 56 | /** 57 | @Summary 58 | This function returns the if the comparator event has occurred or not 59 | 60 | @Description 61 | This routine returns true if the comparator event has occurred. It returns false 62 | if the comparator event has not occurred yet. 63 | 64 | @Param 65 | None. 66 | 67 | @Returns 68 | bool. 69 | 70 | */ 71 | bool CMP2_EventStatusGet(void); 72 | /** 73 | bool CMP2_EventStatusGet(void) 74 | */ 75 | 76 | /** 77 | @Summary 78 | This function resets the event status bit of the comparator. 79 | 80 | @Description 81 | This routine resets the event status bit of the comparator after the comparator 82 | event has occurred. 83 | 84 | @Param 85 | None. 86 | 87 | @Returns 88 | bool. 89 | 90 | */ 91 | void CMP2_EventStatusReset(void); 92 | /** 93 | void CMP2_EventStatusReset(void) 94 | */ 95 | /** 96 | @Summary 97 | This function get the status of the HLMS bit of the blanking function of the comparator. 98 | 99 | @Description 100 | This routine will prevent any asserted ('0' or '1') comparator signal from propagating 101 | 102 | @Param 103 | None. 104 | 105 | @Returns 106 | bool. 107 | */ 108 | void CMP2_ComparatorDisable(void); 109 | /** 110 | void CMP2_ComparatorDisable(void) 111 | */ 112 | /** 113 | @Summary 114 | Disables the comparator module. 115 | 116 | @Description 117 | This routine disables the comparator module. 118 | 119 | @Param 120 | None. 121 | 122 | @Returns 123 | bool. 124 | */ 125 | void CMP2_ComparatorEnable(void); 126 | /** 127 | void CMP2_ComparatorEnable(void) 128 | */ 129 | /** 130 | @Summary 131 | Enables the comparator module. 132 | 133 | @Description 134 | This routine enables the comparator module.. 135 | 136 | @Param 137 | None. 138 | 139 | @Returns 140 | bool. 141 | */ 142 | bool CMP2_HLMSStatusGet(void); 143 | /** 144 | bool CMP2_HLMSStatusGet(void) 145 | */ 146 | 147 | /** 148 | @Summary 149 | Callback for CMP2. 150 | 151 | @Description 152 | This routine is callback for CMP2 153 | 154 | @Param 155 | None. 156 | 157 | @Returns 158 | None 159 | 160 | @Example 161 | Refer to CMP2_Initialize(); for an example 162 | */ 163 | void CMP2_CallBack(void); 164 | 165 | /** 166 | @Summary 167 | Polled implementation 168 | 169 | @Description 170 | This routine is used to implement the tasks for polled implementations. 171 | 172 | @Preconditions 173 | CMP2_Initialize() function should have been 174 | called before calling this function. 175 | 176 | @Returns 177 | None 178 | 179 | @Param 180 | None 181 | 182 | @Example 183 | Refer to CMP2_Initialize(); for an example 184 | 185 | */ 186 | void CMP2_Tasks(void); 187 | 188 | #ifdef __cplusplus // Provide C++ Compatibility 189 | } 190 | #endif 191 | 192 | #endif //_CMP2_H 193 | -------------------------------------------------------------------------------- /src/registers/comparators/cmp3.c: -------------------------------------------------------------------------------- 1 | #include "cmp3.h" 2 | 3 | void CMP3_Initialize(void) { 4 | // PSIDL disabled; 5 | CMSTAT = 0x00; 6 | // CON enabled; CPOL Not Inverted; OPMODE Comparator; EVPOL Disabled; COE disabled; CCH C3IN1-; CREF C3IN1+; CEVT disabled; 7 | CM3CON = 0x8000 & ~(0x8000); //disabling Comparator CON bit 8 | // SELSRCC PWM1L; SELSRCB PWM1L; SELSRCA PWM1L; 9 | CM3MSKSRC = 0x00; 10 | // AANEN disabled; ABNEN disabled; ACNEN disabled; HLMS disabled; OANEN disabled; ABEN disabled; ACEN disabled; AAEN disabled; PAGS disabled; OBEN disabled; OCEN disabled; NAGS disabled; OCNEN disabled; OBNEN disabled; OAEN disabled; 11 | CM3MSKCON = 0x00; 12 | // CFSEL FOSC/2; CFLTREN disabled; CFDIV 1:1; 13 | CM3FLTR = 0x00; 14 | 15 | CM3CONbits.CON = 1; //enabling Comparator CON bit 16 | } 17 | 18 | bool CMP3_OutputStatusGet(void) { 19 | return (CM3CONbits.COUT); 20 | } 21 | 22 | bool CMP3_EventStatusGet(void) { 23 | return (CM3CONbits.CEVT); 24 | } 25 | 26 | void CMP3_EventStatusReset(void) { 27 | CM3CONbits.CEVT = 0; 28 | } 29 | 30 | bool CMP3_HLMSStatusGet(void) { 31 | return (CM3MSKCONbits.HLMS); 32 | } 33 | 34 | void CMP3_ComparatorDisable(void) { 35 | CM3CONbits.CON = 0; 36 | } 37 | 38 | void CMP3_ComparatorEnable(void) { 39 | CM3CONbits.CON = 1; 40 | } 41 | 42 | void __attribute__((weak)) CMP3_CallBack(void) { 43 | // Add your custom callback code here 44 | } 45 | 46 | void CMP3_Tasks(void) { 47 | if (IFS1bits.CMIF) { 48 | // CMP3 callback function 49 | CMP3_CallBack(); 50 | 51 | // Clear the CEVT bit to enable further interrupts 52 | CMP3_EventStatusReset(); 53 | 54 | // clear the CMP3 interrupt flag 55 | IFS1bits.CMIF = 0; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/registers/comparators/cmp3.h: -------------------------------------------------------------------------------- 1 | #ifndef _CMP3_H 2 | #define _CMP3_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef __cplusplus // Provide C++ Compatibility 10 | extern "C" { 11 | #endif 12 | 13 | /** 14 | @Summary 15 | This function initializes Comparator instance : 3 16 | 17 | @Description 18 | This routine initializes the Comparator driver instance for : 3, 19 | making it ready for clients to open and use it. It also initializes any 20 | internal data structures. 21 | 22 | @Param 23 | None. 24 | 25 | @Returns 26 | None 27 | 28 | @Comment 29 | 30 | */ 31 | void CMP3_Initialize(void); 32 | /** 33 | void CMP3_Initialize(void) 34 | */ 35 | 36 | /** 37 | @Summary 38 | This function returns the output of the comparator 39 | 40 | @Description 41 | This routine returns the output of the comparator. It returns a bool which 42 | is the output of the comparator. 43 | 44 | @Param 45 | None. 46 | 47 | @Returns 48 | None 49 | 50 | */ 51 | bool CMP3_OutputStatusGet(void); 52 | /** 53 | bool CMP3_OutputStatusGet(void) 54 | */ 55 | 56 | /** 57 | @Summary 58 | This function returns the if the comparator event has occurred or not 59 | 60 | @Description 61 | This routine returns true if the comparator event has occurred. It returns false 62 | if the comparator event has not occurred yet. 63 | 64 | @Param 65 | None. 66 | 67 | @Returns 68 | bool. 69 | 70 | */ 71 | bool CMP3_EventStatusGet(void); 72 | /** 73 | bool CMP3_EventStatusGet(void) 74 | */ 75 | 76 | /** 77 | @Summary 78 | This function resets the event status bit of the comparator. 79 | 80 | @Description 81 | This routine resets the event status bit of the comparator after the comparator 82 | event has occurred. 83 | 84 | @Param 85 | None. 86 | 87 | @Returns 88 | bool. 89 | 90 | */ 91 | void CMP3_EventStatusReset(void); 92 | /** 93 | void CMP3_EventStatusReset(void) 94 | */ 95 | /** 96 | @Summary 97 | This function get the status of the HLMS bit of the blanking function of the comparator. 98 | 99 | @Description 100 | This routine will prevent any asserted ('0' or '1') comparator signal from propagating 101 | 102 | @Param 103 | None. 104 | 105 | @Returns 106 | bool. 107 | */ 108 | void CMP3_ComparatorDisable(void); 109 | /** 110 | void CMP3_ComparatorDisable(void) 111 | */ 112 | /** 113 | @Summary 114 | Disables the comparator module. 115 | 116 | @Description 117 | This routine disables the comparator module. 118 | 119 | @Param 120 | None. 121 | 122 | @Returns 123 | bool. 124 | */ 125 | void CMP3_ComparatorEnable(void); 126 | /** 127 | void CMP3_ComparatorEnable(void) 128 | */ 129 | /** 130 | @Summary 131 | Enables the comparator module. 132 | 133 | @Description 134 | This routine enables the comparator module.. 135 | 136 | @Param 137 | None. 138 | 139 | @Returns 140 | bool. 141 | */ 142 | bool CMP3_HLMSStatusGet(void); 143 | /** 144 | bool CMP3_HLMSStatusGet(void) 145 | */ 146 | 147 | /** 148 | @Summary 149 | Callback for CMP3. 150 | 151 | @Description 152 | This routine is callback for CMP3 153 | 154 | @Param 155 | None. 156 | 157 | @Returns 158 | None 159 | 160 | @Example 161 | Refer to CMP3_Initialize(); for an example 162 | */ 163 | void CMP3_CallBack(void); 164 | 165 | /** 166 | @Summary 167 | Polled implementation 168 | 169 | @Description 170 | This routine is used to implement the tasks for polled implementations. 171 | 172 | @Preconditions 173 | CMP3_Initialize() function should have been 174 | called before calling this function. 175 | 176 | @Returns 177 | None 178 | 179 | @Param 180 | None 181 | 182 | @Example 183 | Refer to CMP3_Initialize(); for an example 184 | 185 | */ 186 | void CMP3_Tasks(void); 187 | 188 | #ifdef __cplusplus // Provide C++ Compatibility 189 | } 190 | #endif 191 | 192 | #endif //_CMP3_H 193 | -------------------------------------------------------------------------------- /src/registers/comparators/cmp4.c: -------------------------------------------------------------------------------- 1 | #include "cmp4.h" 2 | #include "cmp_params.h" 3 | 4 | void CMP4_Initialize(void) { 5 | 6 | CMP4_InitializeStatus(); 7 | CMP4_InitializeControl(); 8 | CMP4_InitializeMaskSource(); 9 | CMP4_InitializeMaskGatingControl(); 10 | CMP4_InitializeFilterControl(); 11 | 12 | CMP4_ComparatorEnable(); 13 | } 14 | 15 | void CMP4_InitializeStatus(void) { 16 | // Continue operation in idle mode 17 | CMSTATbits.PSIDL = 0; 18 | // Comparator event flags did not happen 19 | CMSTATbits.C1EVT = 0; 20 | CMSTATbits.C2EVT = 0; 21 | CMSTATbits.C3EVT = 0; 22 | CMSTATbits.C4EVT = 0; 23 | // Comparator output status bit is set to VIN+ < VIN- 24 | CMSTATbits.C1OUT = 0; 25 | CMSTATbits.C2OUT = 0; 26 | CMSTATbits.C3OUT = 0; 27 | CMSTATbits.C4OUT = 0; 28 | } 29 | 30 | void CMP4_InitializeControl(void) { 31 | // Comparator is disabled 32 | CM4CONbits.CON = 0; 33 | // Comparator output is internal 34 | CM4CONbits.COE = 0; 35 | // Comparator output is not inverted 36 | CM4CONbits.CPOL = 0; 37 | // Comparator event did not occur 38 | CM4CONbits.CEVT = 0; 39 | // Comparator output is VIN+ < VIN- 40 | CM4CONbits.COUT = 0; 41 | // No trigger or interrupts 42 | CM4CONbits.EVPOL = CMP_TRIGGER_DISABLED; 43 | // VIN+ connects to C4IN1+ pin (AN6 -- CAP Internal Pin) 44 | CM4CONbits.CREF = 0; 45 | // VIN- connects to C4IN- pin (AN7 -- RES Pin) 46 | CM4CONbits.CCH = 0b00; 47 | } 48 | 49 | void CMP4_InitializeMaskSource(void) { 50 | // Mask A 51 | CM4MSKSRCbits.SELSRCA = CMP_MASK_PWM1L; 52 | // Mask B 53 | CM4MSKSRCbits.SELSRCB = CMP_MASK_PWM1L; 54 | // Mask C 55 | CM4MSKSRCbits.SELSRCC = CMP_MASK_PWM1L; 56 | } 57 | 58 | void CMP4_InitializeMaskGatingControl(void) { 59 | // Prevent asserted logic high signals from propagation 60 | CM4MSKCONbits.HLMS = 0; 61 | // OR gate A is not connected 62 | CM4MSKCONbits.OAEN = 0; 63 | CM4MSKCONbits.OANEN = 0; 64 | // OR gate B is not connected 65 | CM4MSKCONbits.OBEN = 0; 66 | CM4MSKCONbits.OBNEN = 0; 67 | // OR gate C is not connected 68 | CM4MSKCONbits.OCEN = 0; 69 | CM4MSKCONbits.OCNEN = 0; 70 | // Inverted AND gate is not connected 71 | CM4MSKCONbits.NAGS = 0; 72 | CM4MSKCONbits.PAGS = 0; 73 | // AND gate A is not connected 74 | CM4MSKCONbits.AAEN = 0; 75 | CM4MSKCONbits.AANEN = 0; 76 | // AND gate B is not connected 77 | CM4MSKCONbits.ABEN = 0; 78 | CM4MSKCONbits.ABNEN = 0; 79 | // AND gate C is not connected 80 | CM4MSKCONbits.ACEN = 0; 81 | CM4MSKCONbits.ACNEN = 0; 82 | } 83 | 84 | void CMP4_InitializeFilterControl(void) { 85 | // Set external clock as filter input clock 86 | CM4FLTRbits.CFSEL = CMP_FILTER_CLOCK_FP; 87 | // Set filter clock divider 88 | CM4FLTRbits.CFDIV = CMP_CLOCK_PRESCALER_1; 89 | // Filter is disabled 90 | CM4FLTRbits.CFLTREN = 0; 91 | } 92 | 93 | void CMP4_SetupComparator(void) { 94 | 95 | CMP4_Initialize(); 96 | // Disable the module until configured 97 | CMP4_ComparatorDisable(); 98 | // VIN- connects to C4IN1- (RES Pin) and VIN+ connects to internal CVREFIN 99 | CM4CONbits.CREF = 1; 100 | // Trigger on High to Low transitions 101 | CM4CONbits.EVPOL = CMP_TRIGGER_HIGH_TO_LOW; 102 | // Comparator output is at C4OUT pin 103 | CM4CONbits.COE = 1; 104 | 105 | // Filter clock pre-scaler 106 | CM4FLTRbits.CFDIV = CMP_CLOCK_PRESCALER_16; 107 | // Enable filter 108 | CM4FLTRbits.CFLTREN = 1; 109 | 110 | // Mask A input 111 | CM4MSKSRCbits.SELSRCA = CMP_MASK_PWM1H; 112 | 113 | // Asserted logic low signals will not propagate 114 | CM4MSKCONbits.HLMS = 1; 115 | // OR gate A is enabled 116 | CM4MSKCONbits.OAEN = 1; 117 | 118 | // Enable comparator module 119 | CMP4_ComparatorEnable(); 120 | PMD3bits.CMPMD = 0; 121 | } 122 | 123 | bool CMP4_OutputStatusGet(void) { 124 | return (CM4CONbits.COUT); 125 | } 126 | 127 | bool CMP4_EventStatusGet(void) { 128 | return (CM4CONbits.CEVT); 129 | } 130 | 131 | void CMP4_EventStatusReset(void) { 132 | CM4CONbits.CEVT = 0; 133 | } 134 | 135 | bool CMP4_HLMSStatusGet(void) { 136 | return (CM4MSKCONbits.HLMS); 137 | } 138 | 139 | void CMP4_ComparatorDisable(void) { 140 | CM4CONbits.CON = 0; 141 | } 142 | 143 | void CMP4_ComparatorEnable(void) { 144 | CM4CONbits.CON = 1; 145 | } 146 | 147 | void __attribute__((weak)) CMP4_CallBack(void) { 148 | // Add your custom callback code here 149 | } 150 | 151 | void CMP4_Tasks(void) { 152 | if (IFS1bits.CMIF) { 153 | // CMP4 callback function 154 | CMP4_CallBack(); 155 | 156 | // Clear the CEVT bit to enable further interrupts 157 | CMP4_EventStatusReset(); 158 | 159 | // clear the CMP4 interrupt flag 160 | IFS1bits.CMIF = 0; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/registers/comparators/cmp4.h: -------------------------------------------------------------------------------- 1 | #ifndef _CMP4_H 2 | #define _CMP4_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef __cplusplus // Provide C++ Compatibility 10 | extern "C" { 11 | #endif 12 | 13 | /** 14 | @Summary 15 | This function initializes Comparator instance : 4 16 | 17 | @Description 18 | This routine initializes the Comparator driver instance for : 4, 19 | making it ready for clients to open and use it. It also initializes any 20 | internal data structures. 21 | 22 | @Param 23 | None. 24 | 25 | @Returns 26 | None 27 | 28 | @Comment 29 | 30 | */ 31 | void CMP4_Initialize(void); 32 | 33 | void CMP4_InitializeStatus(void); 34 | void CMP4_InitializeControl(void); 35 | void CMP4_InitializeMaskSource(void); 36 | void CMP4_InitializeMaskGatingControl(void); 37 | void CMP4_InitializeFilterControl(void); 38 | 39 | /** 40 | @Summary 41 | This function setup CMP4 module as a voltage comparator 42 | 43 | @Description 44 | This routine sets the bits in CMP4 configuration registers to enable the 45 | module as a voltage comparator sensitive to an external source pin (RES) 46 | and set output value in C4OUT pin 47 | 48 | @Param 49 | None. 50 | 51 | @Returns 52 | None 53 | */ 54 | void CMP4_SetupComparator(void); 55 | 56 | /** 57 | @Summary 58 | This function returns the output of the comparator 59 | 60 | @Description 61 | This routine returns the output of the comparator. It returns a bool which 62 | is the output of the comparator. 63 | 64 | @Param 65 | None. 66 | 67 | @Returns 68 | None 69 | 70 | */ 71 | bool CMP4_OutputStatusGet(void); 72 | /** 73 | bool CMP4_OutputStatusGet(void) 74 | */ 75 | 76 | /** 77 | @Summary 78 | This function returns the if the comparator event has occurred or not 79 | 80 | @Description 81 | This routine returns true if the comparator event has occurred. It returns false 82 | if the comparator event has not occurred yet. 83 | 84 | @Param 85 | None. 86 | 87 | @Returns 88 | bool. 89 | 90 | */ 91 | bool CMP4_EventStatusGet(void); 92 | /** 93 | bool CMP4_EventStatusGet(void) 94 | */ 95 | 96 | /** 97 | @Summary 98 | This function resets the event status bit of the comparator. 99 | 100 | @Description 101 | This routine resets the event status bit of the comparator after the comparator 102 | event has occurred. 103 | 104 | @Param 105 | None. 106 | 107 | @Returns 108 | bool. 109 | 110 | */ 111 | void CMP4_EventStatusReset(void); 112 | /** 113 | void CMP4_EventStatusReset(void) 114 | */ 115 | /** 116 | @Summary 117 | This function get the status of the HLMS bit of the blanking function of the comparator. 118 | 119 | @Description 120 | This routine will prevent any asserted ('0' or '1') comparator signal from propagating 121 | 122 | @Param 123 | None. 124 | 125 | @Returns 126 | bool. 127 | */ 128 | void CMP4_ComparatorDisable(void); 129 | /** 130 | void CMP4_ComparatorDisable(void) 131 | */ 132 | /** 133 | @Summary 134 | Disables the comparator module. 135 | 136 | @Description 137 | This routine disables the comparator module. 138 | 139 | @Param 140 | None. 141 | 142 | @Returns 143 | bool. 144 | */ 145 | void CMP4_ComparatorEnable(void); 146 | /** 147 | void CMP4_ComparatorEnable(void) 148 | */ 149 | /** 150 | @Summary 151 | Enables the comparator module. 152 | 153 | @Description 154 | This routine enables the comparator module.. 155 | 156 | @Param 157 | None. 158 | 159 | @Returns 160 | bool. 161 | */ 162 | bool CMP4_HLMSStatusGet(void); 163 | /** 164 | bool CMP4_HLMSStatusGet(void) 165 | */ 166 | 167 | /** 168 | @Summary 169 | Callback for CMP4. 170 | 171 | @Description 172 | This routine is callback for CMP4 173 | 174 | @Param 175 | None. 176 | 177 | @Returns 178 | None 179 | 180 | @Example 181 | Refer to CMP4_Initialize(); for an example 182 | */ 183 | void CMP4_CallBack(void); 184 | 185 | /** 186 | @Summary 187 | Polled implementation 188 | 189 | @Description 190 | This routine is used to implement the tasks for polled implementations. 191 | 192 | @Preconditions 193 | CMP4_Initialize() function should have been 194 | called before calling this function. 195 | 196 | @Returns 197 | None 198 | 199 | @Param 200 | None 201 | 202 | @Example 203 | Refer to CMP4_Initialize(); for an example 204 | 205 | */ 206 | void CMP4_Tasks(void); 207 | 208 | #ifdef __cplusplus // Provide C++ Compatibility 209 | } 210 | #endif 211 | 212 | #endif //_CMP4_H 213 | -------------------------------------------------------------------------------- /src/registers/comparators/cmp_params.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fossasia/pslab-firmware/37b91ab961409715fbfe7159a6a5aba1a0c3e364/src/registers/comparators/cmp_params.c -------------------------------------------------------------------------------- /src/registers/comparators/cmp_params.h: -------------------------------------------------------------------------------- 1 | #ifndef CMP_PARAMS_H 2 | #define CMP_PARAMS_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | typedef enum { 11 | CMP_MASK_PWM1L = 0b0000, 12 | CMP_MASK_PWM1H = 0b0001, 13 | CMP_MASK_PWM2L = 0b0010, 14 | CMP_MASK_PWM2H = 0b0011, 15 | CMP_MASK_PWM3L = 0b0100, 16 | CMP_MASK_PWM3H = 0b0101, 17 | CMP_MASK_PTGO18 = 0b1100, 18 | CMP_MASK_PTGO19 = 0b1101, 19 | CMP_MASK_FLT2 = 0b1110, 20 | CMP_MASK_FLT4 = 0b1111 21 | } CMP_MASK; 22 | 23 | 24 | typedef enum { 25 | CMP_FILTER_CLOCK_FP = 0b000, 26 | CMP_FILTER_CLOCK_FOSC = 0b001, 27 | CMP_FILTER_CLOCK_SYNCO1 = 0b010, 28 | CMP_FILTER_CLOCK_TIMER2 = 0b100, 29 | CMP_FILTER_CLOCK_TIMER3 = 0b101, 30 | CMP_FILTER_CLOCK_TIMER4 = 0b110, 31 | CMP_FILTER_CLOCK_TIMER5 = 0b111 32 | } CMP_FILTER_CLOCK; 33 | 34 | 35 | typedef enum { 36 | CMP_CLOCK_PRESCALER_1 = 0b000, 37 | CMP_CLOCK_PRESCALER_2 = 0b001, 38 | CMP_CLOCK_PRESCALER_4 = 0b010, 39 | CMP_CLOCK_PRESCALER_8 = 0b011, 40 | CMP_CLOCK_PRESCALER_16 = 0b100, 41 | CMP_CLOCK_PRESCALER_32 = 0b101, 42 | CMP_CLOCK_PRESCALER_64 = 0b110, 43 | CMP_CLOCK_PRESCALER_128 = 0b111 44 | } CMP_CLOCK_PRESCALER; 45 | 46 | 47 | typedef enum { 48 | CMP_TRIGGER_DISABLED = 0b00, 49 | CMP_TRIGGER_LOW_TO_HIGH = 0b01, 50 | CMP_TRIGGER_HIGH_TO_LOW = 0b10, 51 | CMP_TRIGGER_EVERY_EVENT = 0b11 52 | } CMP_TRIGGER; 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif /* CMP_PARAMS_H */ 59 | 60 | -------------------------------------------------------------------------------- /src/registers/comparators/cvr.c: -------------------------------------------------------------------------------- 1 | #include "cvr.h" 2 | 3 | void CVR_Initialize(void) { 4 | // (AVDD - AVSS)/2 is disconnected from the CVREF2O pin 5 | CVRCONbits.CVR2OE = 0; 6 | // CVREFIN is generated by the resistor network 7 | CVRCONbits.VREFSEL = 0; 8 | // Comparator voltage reference circuit is powered down 9 | CVRCONbits.CVREN = 0; 10 | // Voltage level is disconnected from then CVREF1O pin 11 | CVRCONbits.CVR1OE = 0; 12 | // CVRSRC/32 step-size 13 | CVRCONbits.CVRR = 0; 14 | // Comparator voltage reference source, CVRSRC = AVDD - AVSS 15 | CVRCONbits.CVRSS = 0; 16 | // CVREFIN = (CVRSRC/4) + (CVR[3:0]/32) x (CVRSRC) 17 | CVRCONbits.CVR = 0b000; 18 | } 19 | 20 | void CVR_ComparatorReference1Connection(bool connect) { 21 | // Voltage level is dis/connect at the CVREF1O pin 22 | CVRCONbits.CVR1OE = connect; 23 | } 24 | 25 | void CVR_ComparatorReference2Connection(bool connect) { 26 | // (AVDD - AVSS)/2 is dis/connect at the CVREF2O pin 27 | CVRCONbits.CVR2OE = connect; 28 | } 29 | 30 | void CVR_SetupComparator(void) { 31 | CVR_Initialize(); 32 | CVR_SetReferenceVoltage(7); // ~ 1.54V 33 | CVR_ComparatorPowerUp(); 34 | } 35 | -------------------------------------------------------------------------------- /src/registers/comparators/cvr.h: -------------------------------------------------------------------------------- 1 | #ifndef _CVR_H 2 | #define _CVR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef __cplusplus // Provide C++ Compatibility 10 | extern "C" { 11 | #endif 12 | 13 | /** 14 | @Summary 15 | This function initializes CVR 16 | 17 | @Description 18 | This routine initializes the CVR driver index, making it 19 | ready for clients to open and use it. It also initializes any internal data 20 | structures. 21 | 22 | @Param 23 | None. 24 | 25 | @Returns 26 | None 27 | 28 | @Comment 29 | 30 | */ 31 | void CVR_Initialize(void); 32 | 33 | /** 34 | @Summary 35 | Comparator Voltage Reference 1 Output Enable bit 36 | 37 | @Description 38 | Voltage level is output on the CVREF1O pin or is disconnected from the 39 | CVREF1O pin 40 | 41 | @Param 42 | bool: connect 43 | 44 | @Returns 45 | None 46 | */ 47 | void CVR_ComparatorReference1Connection(bool connect); 48 | 49 | /** 50 | @Summary 51 | Comparator Voltage Reference 2 Output Enable bit 52 | 53 | @Description 54 | (AVDD - AVSS)/2 is connected to or disconnected from the CVREF2O pin 55 | 56 | @Param 57 | bool: connect 58 | 59 | @Returns 60 | None 61 | */ 62 | void CVR_ComparatorReference2Connection(bool connect); 63 | 64 | /** 65 | @Summary 66 | Configure and power up comparator 67 | 68 | @Description 69 | This routine will setup 1.54 V as reference for comparator and turn it on 70 | 71 | @Param 72 | None 73 | 74 | @Returns 75 | None 76 | */ 77 | void CVR_SetupComparator(void); 78 | 79 | inline static void CVR_ComparatorPowerUp(void) { 80 | CVRCONbits.CVREN = 1; 81 | } 82 | 83 | inline static void CVR_SetReferenceVoltage(uint8_t V) { 84 | CVRCONbits.CVR = V; 85 | } 86 | 87 | #ifdef __cplusplus // Provide C++ Compatibility 88 | } 89 | #endif 90 | 91 | #endif //_CVR_H 92 | -------------------------------------------------------------------------------- /src/registers/comparators/ic1.c: -------------------------------------------------------------------------------- 1 | #include "ic1.h" 2 | 3 | void IC1_Initialize(void) { 4 | IC1_InitializeCON1(); 5 | IC1_InitializeCON2(); 6 | } 7 | 8 | void IC1_InitializeCON1(void) { 9 | // Input capture continues to operate in CPU idle mode 10 | IC1CON1bits.ICSIDL = 0; 11 | // Input capture clock source is set to timer 3 12 | IC1CON1bits.ICTSEL = IC_PARAMS_CAPTURE_TIMER3; 13 | // Interrupt on every capture event 14 | IC1CON1bits.ICI = IC_PARAMS_CAPTURE_INTERRUPT_EVERY_EVENT; 15 | // Capture event flags (Read Only; but settable) 16 | IC1CON1bits.ICOV = 0; // No overflow 17 | IC1CON1bits.ICBNE = 0; // Buffer empty 18 | // Input capture mode is turned off 19 | IC1CON1bits.ICM = IC_PARAMS_CAPTURE_MODE_OFF; 20 | } 21 | 22 | void IC1_InitializeCON2(void) { 23 | // Input capture modules are not concatenated 24 | IC1CON2bits.IC32 = 0; 25 | // Input source is used to sync the capture timer 26 | IC1CON2bits.ICTRIG = 0; 27 | // IC1TMR is cleared and not triggered 28 | IC1CON2bits.TRIGSTAT = 0; 29 | // Input capture source is none 30 | IC1CON2bits.SYNCSEL = IC_PARAMS_CAPTURE_SOURCE_NONE; 31 | } 32 | 33 | void IC1_Start(IC_PARAMS_CAPTURE_MODE mode) { 34 | IC1CON1bits.ICM = mode; 35 | } 36 | 37 | void IC1_Stop(void) { 38 | IC1CON1bits.ICM = IC_PARAMS_CAPTURE_MODE_OFF; 39 | } 40 | 41 | uint16_t IC1_CaptureDataRead(void) { 42 | return (IC1BUF); 43 | } 44 | 45 | void IC1_ManualTriggerSet(void) { 46 | IC1CON2bits.TRIGSTAT = true; 47 | } 48 | 49 | bool IC1_TriggerStatusGet(void) { 50 | return (IC1CON2bits.TRIGSTAT); 51 | } 52 | 53 | void IC1_TriggerStatusClear(void) { 54 | IC1CON2bits.TRIGSTAT = 0; 55 | } 56 | 57 | bool IC1_HasCaptureBufferOverflowed(void) { 58 | return (IC1CON1bits.ICOV); 59 | } 60 | 61 | bool IC1_IsCaptureBufferEmpty(void) { 62 | return (!IC1CON1bits.ICBNE); 63 | } 64 | -------------------------------------------------------------------------------- /src/registers/comparators/ic2.c: -------------------------------------------------------------------------------- 1 | #include "ic2.h" 2 | 3 | void IC2_Initialize(void) { 4 | IC2_InitializeCON1(); 5 | IC2_InitializeCON2(); 6 | } 7 | 8 | void IC2_InitializeCON1(void) { 9 | // Input capture continues to operate in CPU idle mode 10 | IC2CON1bits.ICSIDL = 0; 11 | // Input capture clock source is set to timer 3 12 | IC2CON1bits.ICTSEL = IC_PARAMS_CAPTURE_TIMER3; 13 | // Interrupt on every capture event 14 | IC2CON1bits.ICI = IC_PARAMS_CAPTURE_INTERRUPT_EVERY_EVENT; 15 | // Capture event flags (Read Only; but settable) 16 | IC2CON1bits.ICOV = 0; // No overflow 17 | IC2CON1bits.ICBNE = 0; // Buffer empty 18 | // Input capture mode is turned off 19 | IC2CON1bits.ICM = IC_PARAMS_CAPTURE_MODE_OFF; 20 | } 21 | 22 | void IC2_InitializeCON2(void) { 23 | // Input capture modules are not concatenated 24 | IC2CON2bits.IC32 = 0; 25 | // Input source is used to sync the capture timer 26 | IC2CON2bits.ICTRIG = 0; 27 | // IC2TMR is cleared and not triggered 28 | IC2CON2bits.TRIGSTAT = 0; 29 | // Input capture source is none 30 | IC2CON2bits.SYNCSEL = IC_PARAMS_CAPTURE_SOURCE_NONE; 31 | } 32 | 33 | void IC2_Start(IC_PARAMS_CAPTURE_MODE mode) { 34 | IC2CON1bits.ICM = mode; 35 | } 36 | 37 | void IC2_Stop(void) { 38 | IC2CON1bits.ICM = IC_PARAMS_CAPTURE_MODE_OFF; 39 | } 40 | 41 | uint16_t IC2_CaptureDataRead(void) { 42 | return (IC2BUF); 43 | } 44 | 45 | void IC2_ManualTriggerSet(void) { 46 | IC2CON2bits.TRIGSTAT = true; 47 | } 48 | 49 | bool IC2_TriggerStatusGet(void) { 50 | return (IC2CON2bits.TRIGSTAT); 51 | } 52 | 53 | void IC2_TriggerStatusClear(void) { 54 | IC2CON2bits.TRIGSTAT = 0; 55 | } 56 | 57 | bool IC2_HasCaptureBufferOverflowed(void) { 58 | return (IC2CON1bits.ICOV); 59 | } 60 | 61 | bool IC2_IsCaptureBufferEmpty(void) { 62 | return (!IC2CON1bits.ICBNE); 63 | } 64 | -------------------------------------------------------------------------------- /src/registers/comparators/ic3.c: -------------------------------------------------------------------------------- 1 | #include "ic3.h" 2 | 3 | void IC3_Initialize(void) { 4 | IC3_InitializeCON1(); 5 | IC3_InitializeCON2(); 6 | } 7 | 8 | void IC3_InitializeCON1(void) { 9 | // Input capture continues to operate in CPU idle mode 10 | IC3CON1bits.ICSIDL = 0; 11 | // Input capture clock source is set to timer 3 12 | IC3CON1bits.ICTSEL = IC_PARAMS_CAPTURE_TIMER3; 13 | // Interrupt on every capture event 14 | IC3CON1bits.ICI = IC_PARAMS_CAPTURE_INTERRUPT_EVERY_EVENT; 15 | // Capture event flags (Read Only; but settable) 16 | IC3CON1bits.ICOV = 0; // No overflow 17 | IC3CON1bits.ICBNE = 0; // Buffer empty 18 | // Input capture mode is turned off 19 | IC3CON1bits.ICM = IC_PARAMS_CAPTURE_MODE_OFF; 20 | } 21 | 22 | void IC3_InitializeCON2(void) { 23 | // Input capture modules are not concatenated 24 | IC3CON2bits.IC32 = 0; 25 | // Input source is used to sync the capture timer 26 | IC3CON2bits.ICTRIG = 0; 27 | // IC3TMR is cleared and not triggered 28 | IC3CON2bits.TRIGSTAT = 0; 29 | // Input capture source is none 30 | IC3CON2bits.SYNCSEL = IC_PARAMS_CAPTURE_SOURCE_NONE; 31 | } 32 | 33 | void IC3_Start(IC_PARAMS_CAPTURE_MODE mode) { 34 | IC3CON1bits.ICM = mode; 35 | } 36 | 37 | void IC3_Stop(void) { 38 | IC3CON1bits.ICM = IC_PARAMS_CAPTURE_MODE_OFF; 39 | } 40 | 41 | uint16_t IC3_CaptureDataRead(void) { 42 | return (IC3BUF); 43 | } 44 | 45 | void IC3_ManualTriggerSet(void) { 46 | IC3CON2bits.TRIGSTAT = true; 47 | } 48 | 49 | bool IC3_TriggerStatusGet(void) { 50 | return (IC3CON2bits.TRIGSTAT); 51 | } 52 | 53 | void IC3_TriggerStatusClear(void) { 54 | IC3CON2bits.TRIGSTAT = 0; 55 | } 56 | 57 | bool IC3_HasCaptureBufferOverflowed(void) { 58 | return (IC3CON1bits.ICOV); 59 | } 60 | 61 | bool IC3_IsCaptureBufferEmpty(void) { 62 | return (!IC3CON1bits.ICBNE); 63 | } 64 | -------------------------------------------------------------------------------- /src/registers/comparators/ic4.c: -------------------------------------------------------------------------------- 1 | #include "ic4.h" 2 | #include "../../helpers/interval.h" 3 | 4 | void __attribute__((__interrupt__, no_auto_psv)) _IC4Interrupt(void) { 5 | SetDefaultDIGITAL_STATES(); 6 | IC4_Stop(); 7 | IC4_InterruptFlagClear(); 8 | IC4_InterruptDisable(); 9 | SetDefaultDIGITAL_STATES_ERROR(); 10 | } 11 | 12 | void IC4_Initialize(void) { 13 | IC4_InitializeCON1(); 14 | IC4_InitializeCON2(); 15 | } 16 | 17 | void IC4_InitializeCON1(void) { 18 | // Input capture continues to operate in CPU idle mode 19 | IC4CON1bits.ICSIDL = 0; 20 | // Input capture clock source is set to timer 3 21 | IC4CON1bits.ICTSEL = IC_PARAMS_CAPTURE_TIMER3; 22 | // Interrupt on every capture event 23 | IC4CON1bits.ICI = IC_PARAMS_CAPTURE_INTERRUPT_EVERY_EVENT; 24 | // Capture event flags (Read Only; but settable) 25 | IC4CON1bits.ICOV = 0; // No overflow 26 | IC4CON1bits.ICBNE = 0; // Buffer empty 27 | // Input capture mode is turned off 28 | IC4CON1bits.ICM = IC_PARAMS_CAPTURE_MODE_OFF; 29 | } 30 | 31 | void IC4_InitializeCON2(void) { 32 | // Input capture modules are not concatenated 33 | IC4CON2bits.IC32 = 0; 34 | // Input source is used to sync the capture timer 35 | IC4CON2bits.ICTRIG = 0; 36 | // IC4TMR is cleared and not triggered 37 | IC4CON2bits.TRIGSTAT = 0; 38 | // Input capture source is none 39 | IC4CON2bits.SYNCSEL = IC_PARAMS_CAPTURE_SOURCE_NONE; 40 | } 41 | 42 | void IC4_Start(IC_PARAMS_CAPTURE_MODE mode) { 43 | IC4CON1bits.ICM = mode; 44 | } 45 | 46 | void IC4_Stop(void) { 47 | IC4CON1bits.ICM = IC_PARAMS_CAPTURE_MODE_OFF; 48 | } 49 | 50 | uint16_t IC4_CaptureDataRead(void) { 51 | return (IC4BUF); 52 | } 53 | 54 | void IC4_ManualTriggerSet(void) { 55 | IC4CON2bits.TRIGSTAT = true; 56 | } 57 | 58 | bool IC4_TriggerStatusGet(void) { 59 | return (IC4CON2bits.TRIGSTAT); 60 | } 61 | 62 | void IC4_TriggerStatusClear(void) { 63 | IC4CON2bits.TRIGSTAT = 0; 64 | } 65 | 66 | bool IC4_HasCaptureBufferOverflowed(void) { 67 | return (IC4CON1bits.ICOV); 68 | } 69 | 70 | bool IC4_IsCaptureBufferEmpty(void) { 71 | return (!IC4CON1bits.ICBNE); 72 | } 73 | -------------------------------------------------------------------------------- /src/registers/comparators/ic_params.c: -------------------------------------------------------------------------------- 1 | #include "ic1.h" 2 | #include "ic2.h" 3 | #include "ic3.h" 4 | #include "ic4.h" 5 | #include "../system/pin_manager.h" 6 | 7 | void IC_PARAMS_InitiateAll(void) { 8 | IC1_Initialize(); 9 | IC2_Initialize(); 10 | IC3_Initialize(); 11 | IC4_Initialize(); 12 | } 13 | 14 | void IC_PARAMS_StopAllModules(void) { 15 | IC1_Stop(); 16 | IC2_Stop(); 17 | IC3_Stop(); 18 | IC4_Stop(); 19 | } 20 | 21 | void IC_PARAMS_ClearTriggerStatus(void) { 22 | IC1_TriggerStatusClear(); 23 | IC2_TriggerStatusClear(); 24 | IC3_TriggerStatusClear(); 25 | IC4_TriggerStatusClear(); 26 | } 27 | 28 | void IC_PARAMS_ClearBufferOverflow(void) { 29 | IC1CON1bits.ICOV = 0; 30 | IC2CON1bits.ICOV = 0; 31 | IC3CON1bits.ICOV = 0; 32 | IC4CON1bits.ICOV = 0; 33 | } 34 | 35 | void IC_PARAMS_DisableAllModules(void) { 36 | IC_PARAMS_ClearTriggerStatus(); 37 | IC_PARAMS_StopAllModules(); 38 | IC_PARAMS_ClearBufferOverflow(); 39 | } 40 | 41 | void IC_PARAMS_ManualTriggerAll(void) { 42 | IC1_ManualTriggerSet(); 43 | IC2_ManualTriggerSet(); 44 | IC3_ManualTriggerSet(); 45 | IC4_ManualTriggerSet(); 46 | } 47 | 48 | void IC_PARAMS_UseSourceTo(IC_PARAMS_SOURCE_TASK t) { 49 | IC1_UseSourceTo(t); 50 | IC2_UseSourceTo(t); 51 | IC3_UseSourceTo(t); 52 | IC4_UseSourceTo(t); 53 | } 54 | 55 | void IC_PARAMS_CombineOddEvenModules(void) { 56 | IC1_CombineOddEvenICModules(); 57 | IC2_CombineOddEvenICModules(); 58 | IC3_CombineOddEvenICModules(); 59 | IC4_CombineOddEvenICModules(); 60 | } 61 | 62 | void IC_PARAMS_SetCaptureTimer(IC_PARAMS_CAPTURE_TIMER t) { 63 | IC1_SetCaptureTimer(t); 64 | IC2_SetCaptureTimer(t); 65 | IC3_SetCaptureTimer(t); 66 | IC4_SetCaptureTimer(t); 67 | } 68 | 69 | void IC_PARAMS_ConfigureIntervalCaptureWithIC1AndIC2(uint8_t pin, 70 | IC_PARAMS_CAPTURE_TIMER timer, 71 | IC_PARAMS_CAPTURE_INTERRUPT interrupt, 72 | IC_PARAMS_CAPTURE_MODE mode) { 73 | 74 | IC1_InterruptFlagClear(); 75 | 76 | RPINR7bits.IC1R = PIN_MANAGER_DIGITAL_PINS[pin]; 77 | 78 | IC1_Initialize(); 79 | IC1_CombineOddEvenICModules(); 80 | IC1_SetCaptureTimer(timer); 81 | IC1_InputCaptureInterruptOn(interrupt); 82 | IC1_UseSourceTo(IC_PARAMS_SOURCE_TASK_TRIGGER); 83 | IC1_SetCaptureMode(mode); 84 | 85 | IC2_Initialize(); 86 | IC2_CombineOddEvenICModules(); 87 | IC2_SetCaptureTimer(timer); 88 | IC2_InputCaptureInterruptOn(interrupt); 89 | IC2_UseSourceTo(IC_PARAMS_SOURCE_TASK_TRIGGER); 90 | IC2_SetCaptureMode(mode); 91 | } 92 | 93 | void IC_PARAMS_ConfigureIntervalCaptureWithIC3AndIC4(uint8_t pin, 94 | IC_PARAMS_CAPTURE_TIMER timer, 95 | IC_PARAMS_CAPTURE_INTERRUPT interrupt, 96 | IC_PARAMS_CAPTURE_MODE mode) { 97 | 98 | IC3_InterruptFlagClear(); 99 | 100 | RPINR8bits.IC3R = PIN_MANAGER_DIGITAL_PINS[pin]; 101 | 102 | IC3_Initialize(); 103 | IC3_CombineOddEvenICModules(); 104 | IC3_SetCaptureTimer(timer); 105 | IC3_InputCaptureInterruptOn(interrupt); 106 | IC3_UseSourceTo(IC_PARAMS_SOURCE_TASK_TRIGGER); 107 | IC3_SetCaptureMode(mode); 108 | 109 | IC4_Initialize(); 110 | IC4_CombineOddEvenICModules(); 111 | IC4_SetCaptureTimer(timer); 112 | IC4_InputCaptureInterruptOn(interrupt); 113 | IC4_UseSourceTo(IC_PARAMS_SOURCE_TASK_TRIGGER); 114 | IC4_SetCaptureMode(mode); 115 | } 116 | -------------------------------------------------------------------------------- /src/registers/comparators/oc1.c: -------------------------------------------------------------------------------- 1 | #include "oc1.h" 2 | 3 | static uint16_t gOC1Mode; 4 | 5 | void OC1_Initialize(void) { 6 | OC1_InitializeCON1(); 7 | OC1_InitializeCON2(); 8 | OC1RS = 0x00; 9 | OC1R = 0x00; 10 | 11 | gOC1Mode = OC1CON1bits.OCM; 12 | } 13 | 14 | void OC1_InitializeCON1(void) { 15 | // Output Compare 1 continues to operate in CPU Idle mode 16 | OC1CON1bits.OCSIDL = 0; 17 | // Output Compare Clock Select is T2CLK 18 | OC1CON1bits.OCTSEL = 0b000; 19 | // Output Compare Fault B input (OCFB) is disabled 20 | OC1CON1bits.ENFLTB = 0; 21 | // Output Compare Fault A input (OCFA) is disabled 22 | OC1CON1bits.ENFLTA = 0; 23 | // No PWM Fault B condition on OCFB pin has occurred 24 | OC1CON1bits.OCFLTB = 0; 25 | // No PWM Fault A condition on OCFA pin has occurred 26 | OC1CON1bits.OCFLTA = 0; 27 | // TRIGSTAT is cleared only by software 28 | OC1CON1bits.TRIGMODE = 0; 29 | // Output compare channel is disabled 30 | OC1CON1bits.OCM = 0b000; 31 | } 32 | 33 | void OC1_InitializeCON2(void) { 34 | // Fault mode is maintained until the Fault source is removed and a new PWM period starts 35 | OC1CON2bits.FLTMD = 0; 36 | // PWM output is driven low on a Fault 37 | OC1CON2bits.FLTOUT = 0; 38 | // OC1 pin I/O state is defined by the FLTOUT bit on a Fault condition 39 | OC1CON2bits.FLTTRIEN = 0; 40 | // OC1 output is not inverted 41 | OC1CON2bits.OCINV = 0; 42 | // Cascade module operation is disabled 43 | OC1CON2bits.OC32 = 0; 44 | // Synchronizes OCx with the source designated by the SYNCSELx bits 45 | OC1CON2bits.OCTRIG = 0; 46 | // Timer source has not been triggered and is being held clear 47 | OC1CON2bits.TRIGSTAT = 0; 48 | // Output Compare 1 module drives the OC3 pin 49 | OC1CON2bits.OCTRIS = 0; 50 | // No Sync or Trigger source 51 | OC1CON2bits.SYNCSEL = 0b00000; 52 | } 53 | 54 | void OC1_Start(void) { 55 | OC1CON1bits.OCM = gOC1Mode; 56 | } 57 | 58 | void OC1_Stop(void) { 59 | OC1CON1bits.OCM = 0; 60 | } 61 | 62 | void OC1_SecondaryValueSet(uint16_t secVal) { 63 | OC1RS = secVal; 64 | } 65 | 66 | void OC1_PrimaryValueSet(uint16_t priVal) { 67 | OC1R = priVal; 68 | } 69 | 70 | bool OC1_IsCompareCycleComplete(void) { 71 | return (IFS0bits.OC1IF); 72 | } 73 | 74 | bool OC1_FaultStatusGet(OC1_FAULTS faultNum) { 75 | bool status = true; 76 | /* Return the status of the fault condition */ 77 | 78 | switch (faultNum) { 79 | case OC1_FAULT0: 80 | status = OC1CON1bits.OCFLT0; 81 | break; 82 | case OC1_FAULT1: 83 | status = OC1CON1bits.OCFLT1; 84 | break; 85 | } 86 | 87 | return (status); 88 | } 89 | 90 | void OC1_FaultStatusClear(OC1_FAULTS faultNum) { 91 | 92 | switch (faultNum) { 93 | case OC1_FAULT0: 94 | OC1CON1bits.OCFLT0 = 0; 95 | break; 96 | case OC1_FAULT1: 97 | OC1CON1bits.OCFLT1 = 0; 98 | break; 99 | } 100 | } 101 | 102 | void OC1_ManualTriggerSet(void) { 103 | OC1CON2bits.TRIGSTAT = true; 104 | } 105 | 106 | bool OC1_TriggerStatusGet(void) { 107 | return ( OC1CON2bits.TRIGSTAT); 108 | } 109 | 110 | void OC1_TriggerStatusClear(void) { 111 | /* Clears the trigger status */ 112 | OC1CON2bits.TRIGSTAT = 0; 113 | } 114 | -------------------------------------------------------------------------------- /src/registers/comparators/oc2.c: -------------------------------------------------------------------------------- 1 | #include "oc2.h" 2 | 3 | static uint16_t gOC2Mode; 4 | 5 | void OC2_Initialize(void) { 6 | OC2_InitializeCON1(); 7 | OC2_InitializeCON2(); 8 | OC2RS = 0x00; 9 | OC2R = 0x00; 10 | 11 | gOC2Mode = OC2CON1bits.OCM; 12 | } 13 | 14 | void OC2_InitializeCON1(void) { 15 | // Output Compare 2 continues to operate in CPU Idle mode 16 | OC2CON1bits.OCSIDL = 0; 17 | // Output Compare Clock Select is T2CLK 18 | OC2CON1bits.OCTSEL = 0b000; 19 | // Output Compare Fault B input (OCFB) is disabled 20 | OC2CON1bits.ENFLTB = 0; 21 | // Output Compare Fault A input (OCFA) is disabled 22 | OC2CON1bits.ENFLTA = 0; 23 | // No PWM Fault B condition on OCFB pin has occurred 24 | OC2CON1bits.OCFLTB = 0; 25 | // No PWM Fault A condition on OCFA pin has occurred 26 | OC2CON1bits.OCFLTA = 0; 27 | // TRIGSTAT is cleared only by software 28 | OC2CON1bits.TRIGMODE = 0; 29 | // Output compare channel is disabled 30 | OC2CON1bits.OCM = 0b000; 31 | } 32 | 33 | void OC2_InitializeCON2(void) { 34 | // Fault mode is maintained until the Fault source is removed and a new PWM period starts 35 | OC2CON2bits.FLTMD = 0; 36 | // PWM output is driven low on a Fault 37 | OC2CON2bits.FLTOUT = 0; 38 | // OC2 pin I/O state is defined by the FLTOUT bit on a Fault condition 39 | OC2CON2bits.FLTTRIEN = 0; 40 | // OC2 output is not inverted 41 | OC2CON2bits.OCINV = 0; 42 | // Cascade module operation is disabled 43 | OC2CON2bits.OC32 = 0; 44 | // Synchronizes OCx with the source designated by the SYNCSELx bits 45 | OC2CON2bits.OCTRIG = 0; 46 | // Timer source has not been triggered and is being held clear 47 | OC2CON2bits.TRIGSTAT = 0; 48 | // Output Compare 2 module drives the OC2 pin 49 | OC2CON2bits.OCTRIS = 0; 50 | // No Sync or Trigger source 51 | OC2CON2bits.SYNCSEL = 0b00000; 52 | } 53 | 54 | void OC2_Start(void) { 55 | OC2CON1bits.OCM = gOC2Mode; 56 | } 57 | 58 | void OC2_Stop(void) { 59 | OC2CON1bits.OCM = 0; 60 | } 61 | 62 | void OC2_SecondaryValueSet(uint16_t secVal) { 63 | OC2RS = secVal; 64 | } 65 | 66 | void OC2_PrimaryValueSet(uint16_t priVal) { 67 | OC2R = priVal; 68 | } 69 | 70 | bool OC2_IsCompareCycleComplete(void) { 71 | return (IFS0bits.OC2IF); 72 | } 73 | 74 | bool OC2_FaultStatusGet(OC2_FAULTS faultNum) { 75 | bool status = true; 76 | /* Return the status of the fault condition */ 77 | 78 | switch (faultNum) { 79 | case OC2_FAULT0: 80 | status = OC2CON1bits.OCFLT0; 81 | break; 82 | case OC2_FAULT1: 83 | status = OC2CON1bits.OCFLT1; 84 | break; 85 | } 86 | 87 | return (status); 88 | } 89 | 90 | void OC2_FaultStatusClear(OC2_FAULTS faultNum) { 91 | 92 | switch (faultNum) { 93 | case OC2_FAULT0: 94 | OC2CON1bits.OCFLT0 = 0; 95 | break; 96 | case OC2_FAULT1: 97 | OC2CON1bits.OCFLT1 = 0; 98 | break; 99 | } 100 | } 101 | 102 | void OC2_ManualTriggerSet(void) { 103 | OC2CON2bits.TRIGSTAT = true; 104 | } 105 | 106 | bool OC2_TriggerStatusGet(void) { 107 | return ( OC2CON2bits.TRIGSTAT); 108 | } 109 | 110 | void OC2_TriggerStatusClear(void) { 111 | /* Clears the trigger status */ 112 | OC2CON2bits.TRIGSTAT = 0; 113 | } 114 | -------------------------------------------------------------------------------- /src/registers/comparators/oc3.c: -------------------------------------------------------------------------------- 1 | #include "oc3.h" 2 | 3 | static uint16_t gOC3Mode; 4 | 5 | void OC3_Initialize(void) { 6 | OC3_InitializeCON1(); 7 | OC3_InitializeCON2(); 8 | OC3RS = 0x00; 9 | OC3R = 0x00; 10 | 11 | gOC3Mode = OC3CON1bits.OCM; 12 | } 13 | 14 | void OC3_InitializeCON1(void) { 15 | // Output Compare 3 continues to operate in CPU Idle mode 16 | OC3CON1bits.OCSIDL = 0; 17 | // Output Compare Clock Select is T2CLK 18 | OC3CON1bits.OCTSEL = 0b000; 19 | // Output Compare Fault B input (OCFB) is disabled 20 | OC3CON1bits.ENFLTB = 0; 21 | // Output Compare Fault A input (OCFA) is disabled 22 | OC3CON1bits.ENFLTA = 0; 23 | // No PWM Fault B condition on OCFB pin has occurred 24 | OC3CON1bits.OCFLTB = 0; 25 | // No PWM Fault A condition on OCFA pin has occurred 26 | OC3CON1bits.OCFLTA = 0; 27 | // TRIGSTAT is cleared only by software 28 | OC3CON1bits.TRIGMODE = 0; 29 | // Output compare channel is disabled 30 | OC3CON1bits.OCM = 0b000; 31 | } 32 | 33 | void OC3_InitializeCON2(void) { 34 | // Fault mode is maintained until the Fault source is removed and a new PWM period starts 35 | OC3CON2bits.FLTMD = 0; 36 | // PWM output is driven low on a Fault 37 | OC3CON2bits.FLTOUT = 0; 38 | // OC3 pin I/O state is defined by the FLTOUT bit on a Fault condition 39 | OC3CON2bits.FLTTRIEN = 0; 40 | // OC3 output is not inverted 41 | OC3CON2bits.OCINV = 0; 42 | // Cascade module operation is disabled 43 | OC3CON2bits.OC32 = 0; 44 | // Synchronizes OCx with the source designated by the SYNCSELx bits 45 | OC3CON2bits.OCTRIG = 0; 46 | // Timer source has not been triggered and is being held clear 47 | OC3CON2bits.TRIGSTAT = 0; 48 | // Output Compare 3 module drives the OC3 pin 49 | OC3CON2bits.OCTRIS = 0; 50 | // No Sync or Trigger source 51 | OC3CON2bits.SYNCSEL = 0b00000; 52 | } 53 | 54 | void OC3_Start(void) { 55 | OC3CON1bits.OCM = gOC3Mode; 56 | } 57 | 58 | void OC3_Stop(void) { 59 | OC3CON1bits.OCM = 0; 60 | } 61 | 62 | void OC3_SecondaryValueSet(uint16_t secVal) { 63 | OC3RS = secVal; 64 | } 65 | 66 | void OC3_PrimaryValueSet(uint16_t priVal) { 67 | OC3R = priVal; 68 | } 69 | 70 | bool OC3_IsCompareCycleComplete(void) { 71 | return (IFS1bits.OC3IF); 72 | } 73 | 74 | bool OC3_FaultStatusGet(OC3_FAULTS faultNum) { 75 | bool status = true; 76 | /* Return the status of the fault condition */ 77 | 78 | switch (faultNum) { 79 | case OC3_FAULT0: 80 | status = OC3CON1bits.OCFLT0; 81 | break; 82 | case OC3_FAULT1: 83 | status = OC3CON1bits.OCFLT1; 84 | break; 85 | } 86 | 87 | return (status); 88 | } 89 | 90 | void OC3_FaultStatusClear(OC3_FAULTS faultNum) { 91 | 92 | switch (faultNum) { 93 | case OC3_FAULT0: 94 | OC3CON1bits.OCFLT0 = 0; 95 | break; 96 | case OC3_FAULT1: 97 | OC3CON1bits.OCFLT1 = 0; 98 | break; 99 | } 100 | } 101 | 102 | void OC3_ManualTriggerSet(void) { 103 | OC3CON2bits.TRIGSTAT = true; 104 | } 105 | 106 | bool OC3_TriggerStatusGet(void) { 107 | return ( OC3CON2bits.TRIGSTAT); 108 | } 109 | 110 | void OC3_TriggerStatusClear(void) { 111 | /* Clears the trigger status */ 112 | OC3CON2bits.TRIGSTAT = 0; 113 | } 114 | -------------------------------------------------------------------------------- /src/registers/comparators/oc4.c: -------------------------------------------------------------------------------- 1 | #include "oc4.h" 2 | 3 | static uint16_t gOC4Mode; 4 | 5 | void OC4_Initialize(void) { 6 | OC4_InitializeCON1(); 7 | OC4_InitializeCON2(); 8 | OC4RS = 0x00; 9 | OC4R = 0x00; 10 | 11 | gOC4Mode = OC4CON1bits.OCM; 12 | } 13 | 14 | void OC4_InitializeCON1(void) { 15 | // Output Compare 4 continues to operate in CPU Idle mode 16 | OC4CON1bits.OCSIDL = 0; 17 | // Output Compare Clock Select is T2CLK 18 | OC4CON1bits.OCTSEL = 0b000; 19 | // Output Compare Fault B input (OCFB) is disabled 20 | OC4CON1bits.ENFLTB = 0; 21 | // Output Compare Fault A input (OCFA) is disabled 22 | OC4CON1bits.ENFLTA = 0; 23 | // No PWM Fault B condition on OCFB pin has occurred 24 | OC4CON1bits.OCFLTB = 0; 25 | // No PWM Fault A condition on OCFA pin has occurred 26 | OC4CON1bits.OCFLTA = 0; 27 | // TRIGSTAT is cleared only by software 28 | OC4CON1bits.TRIGMODE = 0; 29 | // Output compare channel is disabled 30 | OC4CON1bits.OCM = 0b000; 31 | } 32 | 33 | void OC4_InitializeCON2(void) { 34 | // Fault mode is maintained until the Fault source is removed and a new PWM period starts 35 | OC4CON2bits.FLTMD = 0; 36 | // PWM output is driven low on a Fault 37 | OC4CON2bits.FLTOUT = 0; 38 | // OC4 pin I/O state is defined by the FLTOUT bit on a Fault condition 39 | OC4CON2bits.FLTTRIEN = 0; 40 | // OC4 output is not inverted 41 | OC4CON2bits.OCINV = 0; 42 | // Cascade module operation is disabled 43 | OC4CON2bits.OC32 = 0; 44 | // Synchronizes OCx with the source designated by the SYNCSELx bits 45 | OC4CON2bits.OCTRIG = 0; 46 | // Timer source has not been triggered and is being held clear 47 | OC4CON2bits.TRIGSTAT = 0; 48 | // Output Compare 4 module drives the OC4 pin 49 | OC4CON2bits.OCTRIS = 0; 50 | // No Sync or Trigger source 51 | OC4CON2bits.SYNCSEL = 0b00000; 52 | } 53 | 54 | void __attribute__((weak)) OC4_CallBack(void) { 55 | // Add your custom callback code here 56 | } 57 | 58 | void OC4_Tasks(void) { 59 | if (IFS1bits.OC4IF) { 60 | // OC4 callback function 61 | OC4_CallBack(); 62 | IFS1bits.OC4IF = 0; 63 | } 64 | } 65 | 66 | void OC4_Start(void) { 67 | OC4CON1bits.OCM = gOC4Mode; 68 | } 69 | 70 | void OC4_Stop(void) { 71 | OC4CON1bits.OCM = 0; 72 | } 73 | 74 | void OC4_SecondaryValueSet(uint16_t secVal) { 75 | OC4RS = secVal; 76 | } 77 | 78 | void OC4_PrimaryValueSet(uint16_t priVal) { 79 | OC4R = priVal; 80 | } 81 | 82 | bool OC4_IsCompareCycleComplete(void) { 83 | return (IFS1bits.OC4IF); 84 | } 85 | 86 | bool OC4_FaultStatusGet(OC4_FAULTS faultNum) { 87 | bool status = true; 88 | /* Return the status of the fault condition */ 89 | 90 | switch (faultNum) { 91 | case OC4_FAULT0: 92 | status = OC4CON1bits.OCFLT0; 93 | break; 94 | case OC4_FAULT1: 95 | status = OC4CON1bits.OCFLT1; 96 | break; 97 | } 98 | 99 | return (status); 100 | } 101 | 102 | void OC4_FaultStatusClear(OC4_FAULTS faultNum) { 103 | 104 | switch (faultNum) { 105 | case OC4_FAULT0: 106 | OC4CON1bits.OCFLT0 = 0; 107 | break; 108 | case OC4_FAULT1: 109 | OC4CON1bits.OCFLT1 = 0; 110 | break; 111 | } 112 | } 113 | 114 | void OC4_ManualTriggerSet(void) { 115 | OC4CON2bits.TRIGSTAT = true; 116 | } 117 | 118 | bool OC4_TriggerStatusGet(void) { 119 | return ( OC4CON2bits.TRIGSTAT); 120 | } 121 | 122 | void OC4_TriggerStatusClear(void) { 123 | /* Clears the trigger status */ 124 | OC4CON2bits.TRIGSTAT = 0; 125 | } 126 | -------------------------------------------------------------------------------- /src/registers/converters/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(pslab-firmware.elf PRIVATE 2 | adc1.c 3 | ctmu.c 4 | ) 5 | 6 | target_include_directories(pslab-firmware.elf 7 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 8 | 9 | -------------------------------------------------------------------------------- /src/registers/converters/adc_module_features.h: -------------------------------------------------------------------------------- 1 | #ifndef ADC_MODULE_FEATURES 2 | #define ADC_MODULE_FEATURES 3 | 4 | #ifdef __cplusplus // Provide C++ Compatibility 5 | extern "C" { 6 | #endif 7 | 8 | /******************************************************************************* 9 | ******************************************************************************** 10 | ******************************************************************************** 11 | ********IMPORTANT******** 12 | 13 | This file defines the ADC module feature C-macros available 14 | on the selected device. The macros defined in this file provides the 15 | flexibility to easily migrate the user application to other device which might 16 | have varied feature list. 17 | 18 | The file has to be manually included in main.c, if the user intends to migrate the 19 | application to another device which might have varied feature list. 20 | 21 | 22 | ***************The content in this file is strictly "read only" and should 23 | not be altered. Failing to do so, the migration is not guaranteed.************* 24 | 25 | ******************************************************************************** 26 | ******************************************************************************** 27 | ********************************************************************************/ 28 | 29 | /******************************************************************************* 30 | Macros defined for features supported in the device 31 | *******************************************************************************/ 32 | 33 | //None 34 | 35 | /******************************************************************************* 36 | Macros defined for features not supported in the device 37 | *******************************************************************************/ 38 | 39 | /** ADC POWER ENABLE FEATURE 40 | 41 | @Summary 42 | Defines the macro associated with ADC core power enable. 43 | 44 | @APIs Supported: 45 | None 46 | 47 | @Remarks: 48 | None 49 | */ 50 | #define ADC_POWER_ENABLE_FEATURE_AVAILABLE 0 51 | 52 | /** ADC CALIBRATION FEATURE 53 | 54 | @Summary 55 | Defines the macro associated with ADC core calibration. 56 | 57 | @APIs Supported: 58 | None 59 | 60 | Refer driver header file for detailed description of the APIs. 61 | 62 | @Remarks: 63 | None 64 | */ 65 | #define ADC_CALIBRATION_FEATURE_AVAILABLE 0 66 | 67 | /** ADC COMPARATOR FEATURE 68 | 69 | @Summary 70 | Defines the macro associated with ADC comparator feature. 71 | 72 | @APIs Supported: 73 | None 74 | 75 | @Remarks: 76 | None 77 | */ 78 | #define ADC_COMPARATOR_FEATURE_AVAILABLE 0 79 | 80 | /** ADC INDIVIDUAL CHANNEL INTERRUPT FEATURE 81 | 82 | @Summary 83 | Defines the macro associated with individual channel interrupts. 84 | 85 | @APIs Supported: 86 | None 87 | 88 | @Remarks: 89 | None 90 | */ 91 | #define ADC_INDIVIDUAL_CHANNEL_INTERRUPT_FEATURE_AVAILABLE 0 92 | 93 | #ifdef __cplusplus // Provide C++ Compatibility 94 | } 95 | #endif 96 | 97 | #endif //ADC_MODULE_FEATURES 98 | -------------------------------------------------------------------------------- /src/registers/converters/ctmu.c: -------------------------------------------------------------------------------- 1 | #include "../../bus/uart/uart.h" 2 | #include "../../commands.h" 3 | #include "../../helpers/delay.h" 4 | #include "ctmu.h" 5 | 6 | void CTMU_Initialize(void) { 7 | 8 | CTMU_InitializeCON1(); 9 | CTMU_InitializeCON2(); 10 | // Nominal current output level is set by IRNG 11 | CTMUICONbits.ITRIM = 0b000000; 12 | // Current source output level is set to 1000 times the base current 13 | CTMUICONbits.IRNG = 0b00; 14 | } 15 | 16 | void CTMU_InitializeCON1(void) { 17 | // CTMU module is disabled 18 | CTMUCON1bits.CTMUEN = 0; 19 | // CTMU module continues operating in idle modes 20 | CTMUCON1bits.CTMUSIDL = 0; 21 | // Disables edge delay generation 22 | CTMUCON1bits.TGEN = 0; 23 | // Software is used to trigger edges 24 | CTMUCON1bits.EDGEN = 0; 25 | // No edge sequence is needed 26 | CTMUCON1bits.EDGSEQEN = 0; 27 | // Analog current source output is not grounded 28 | CTMUCON1bits.IDISSEN = 0; 29 | // CTMU does not trigger ADC conversion 30 | CTMUCON1bits.CTTRIG = 0; 31 | } 32 | 33 | void CTMU_InitializeCON2(void) { 34 | // Edge 1 is level sensitive 35 | CTMUCON2bits.EDG1MOD = 0; 36 | // Edge 1 is programmed for a negative edge response 37 | CTMUCON2bits.EDG1POL = 0; 38 | // Edge 1 source is Timer 1 module 39 | CTMUCON2bits.EDG1SEL = 0b0000; 40 | // Edge 1 has not occurred 41 | CTMUCON2bits.EDG1STAT = 0; 42 | // Edge 2 is level sensitive 43 | CTMUCON2bits.EDG2MOD = 0; 44 | // Edge 2 is programmed for a negative edge response 45 | CTMUCON2bits.EDG2POL = 0; 46 | // Edge 2 source is IC1 module 47 | CTMUCON2bits.EDG2SEL = 0b0000; 48 | // Edge 2 has not occurred 49 | CTMUCON2bits.EDG2STAT = 0; 50 | } 51 | 52 | response_t CTMU_Start(void) { 53 | 54 | uint8_t config = UART1_Read(); 55 | uint8_t current_trim = UART1_Read(); 56 | 57 | CTMU_Initialize(); 58 | CTMUCON1bits.TGEN = (config >> 7) & 0x1; 59 | CTMUICONbits.ITRIM = current_trim; 60 | CTMUICONbits.IRNG = config & 0x7F; 61 | CTMU_Enable(); 62 | DELAY_us(1000); 63 | CTMU_EnableEdge1(); 64 | 65 | return SUCCESS; 66 | } 67 | 68 | response_t CTMU_Stop(void) { 69 | CTMU_DisableModule(); 70 | return SUCCESS; 71 | } 72 | -------------------------------------------------------------------------------- /src/registers/converters/ctmu.h: -------------------------------------------------------------------------------- 1 | #ifndef CTMU_H 2 | #define CTMU_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif /* __cplusplus */ 9 | 10 | void CTMU_Initialize(void); 11 | 12 | void CTMU_InitializeCON1(void); 13 | void CTMU_InitializeCON2(void); 14 | 15 | inline static void CTMU_Enable(void) { 16 | CTMUCON1bits.CTMUEN = 1; 17 | } 18 | 19 | inline static void CTMU_Disable(void) { 20 | CTMUCON1bits.CTMUEN = 0; 21 | } 22 | 23 | inline static void CTMU_DrainOutput(void) { 24 | CTMUCON1bits.IDISSEN = 1; 25 | } 26 | 27 | inline static void CTMU_FloatOutput(void) { 28 | CTMUCON1bits.IDISSEN = 0; 29 | } 30 | 31 | inline static void CTMU_EnableEdge1(void) { 32 | CTMUCON2bits.EDG1STAT = 1; 33 | } 34 | 35 | inline static void CTMU_DisableEdge1(void) { 36 | CTMUCON2bits.EDG1STAT = 0; 37 | } 38 | 39 | inline static void CTMU_EnableEdge2(void) { 40 | CTMUCON2bits.EDG2STAT = 1; 41 | } 42 | 43 | inline static void CTMU_DisableEdge2(void) { 44 | CTMUCON2bits.EDG2STAT = 0; 45 | } 46 | 47 | inline static void CTMU_EnableEdgeDelayGeneration(void) { 48 | CTMUCON1bits.TGEN = 1; 49 | } 50 | 51 | inline static void CTMU_DisableEdgeDelayGeneration(void) { 52 | CTMUCON1bits.TGEN = 0; 53 | } 54 | 55 | inline static void CTMU_DisableModule(void) { 56 | CTMU_Disable(); 57 | CTMU_DisableEdge1(); 58 | CTMU_DisableEdge2(); 59 | CTMU_DisableEdgeDelayGeneration(); 60 | } 61 | 62 | /** 63 | * @brief Start Charge Time Measurement Unit 64 | * 65 | * @description 66 | * This command function takes two arguments over serial: 67 | * 1. (uint8) Configuration byte: 68 | * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 69 | * | DG | CSO | 70 | * DG: Delay generator enable/disable (1/0) 71 | * CSO: Current source output: 72 | * 00: Base * 1000 73 | * 01: Base = 0.53 uA 74 | * 10: Base * 10 75 | * 11: Base * 100 76 | * 2. (uint8) Current trim 77 | * 78 | * It returns nothing over serial. 79 | * It sends an acknowledge byte (SUCCESS). 80 | * 81 | * @return SUCCESS 82 | */ 83 | response_t CTMU_Start(void); 84 | 85 | /** 86 | * @brief Stop Charge Time Measurement Unit 87 | * 88 | * @description 89 | * This command function does not take any arguments over serial. It stops 90 | * and disables CTMU module. 91 | * 92 | * It returns nothing over serial. 93 | * It sends an acknowledge byte (SUCCESS). 94 | * 95 | * @return SUCCESS 96 | */ 97 | response_t CTMU_Stop(void); 98 | 99 | 100 | #ifdef __cplusplus 101 | } 102 | #endif /* __cplusplus */ 103 | 104 | #endif /* CTMU_H */ 105 | -------------------------------------------------------------------------------- /src/registers/memory/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(pslab-firmware.elf PRIVATE 2 | dma.c 3 | ) 4 | 5 | target_include_directories(pslab-firmware.elf 6 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 7 | 8 | -------------------------------------------------------------------------------- /src/registers/system/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(pslab-firmware.elf PRIVATE 2 | clock.c 3 | interrupt_manager.c 4 | pin_manager.c 5 | system.c 6 | ) 7 | 8 | target_include_directories(pslab-firmware.elf 9 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 10 | 11 | -------------------------------------------------------------------------------- /src/registers/system/clock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "xc.h" 3 | #include "clock.h" 4 | 5 | void CLOCK_Initialize(void) { 6 | // FRCDIV FRC/2; PLLPRE 3; DOZE 1:8; PLLPOST 1:2; DOZEN disabled; ROI disabled; 7 | CLKDIVbits.PLLPOST = 0; 8 | CLKDIVbits.PLLPRE = 1; 9 | // TUN Center frequency; 10 | OSCTUN = 0x00; 11 | // ROON disabled; ROSEL FOSC; RODIV 0; ROSSLP disabled; 12 | REFOCON = 0x00; 13 | // PLLDIV 62 + 2; 14 | PLLFBD = 0x3E; 15 | // AD1MD enabled; T3MD enabled; T4MD enabled; T1MD enabled; U2MD enabled; T2MD enabled; U1MD enabled; SPI2MD enabled; SPI1MD enabled; T5MD enabled; I2C1MD enabled; 16 | PMD1 = 0x00; 17 | // IC4MD enabled; IC3MD enabled; OC1MD enabled; IC2MD enabled; OC2MD enabled; IC1MD enabled; OC3MD enabled; OC4MD enabled; 18 | PMD2 = 0x00; 19 | // CMPMD enabled; CRCMD enabled; I2C2MD enabled; 20 | PMD3 = 0x00; 21 | // CTMUMD enabled; REFOMD enabled; 22 | PMD4 = 0x00; 23 | // PTGMD enabled; DMA0MD enabled; 24 | PMD7 = 0x00; 25 | // CF no clock failure; NOSC PRIPLL; CLKLOCK unlocked; OSWEN Switch is Complete; 26 | __builtin_write_OSCCONH((uint8_t) (0x03)); 27 | __builtin_write_OSCCONL(OSCCON | (uint8_t) (0x01)); 28 | // Wait for Clock switch to occur 29 | while (OSCCONbits.OSWEN != 0); 30 | while (OSCCONbits.LOCK != 1); 31 | } 32 | -------------------------------------------------------------------------------- /src/registers/system/clock.h: -------------------------------------------------------------------------------- 1 | #ifndef CLOCK_H 2 | #define CLOCK_H 3 | 4 | /** 5 | Section: Included Files 6 | */ 7 | 8 | #include 9 | 10 | #ifndef _XTAL_FREQ 11 | #define _XTAL_FREQ 128000000UL 12 | #endif 13 | 14 | #define CLOCK_SystemFrequencyGet() (128000000UL) 15 | 16 | #define CLOCK_PeripheralFrequencyGet() (CLOCK_SystemFrequencyGet() / 2) 17 | 18 | #define CLOCK_InstructionFrequencyGet() (CLOCK_SystemFrequencyGet() / 2) 19 | /** 20 | * @Param 21 | none 22 | * @Returns 23 | none 24 | * @Description 25 | Initializes the oscillator to the default states configured in the 26 | * MCC GUI 27 | * @Example 28 | CLOCK_Initialize(void); 29 | */ 30 | void CLOCK_Initialize(void); 31 | 32 | 33 | #endif /* CLOCK_H */ 34 | -------------------------------------------------------------------------------- /src/registers/system/interrupt_manager.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../../instruments/logicanalyzer.h" 5 | #include "../timers/tmr2.h" 6 | #include "../../helpers/interval.h" 7 | #include "../comparators/ic_params.h" 8 | #include "interrupt_manager.h" 9 | 10 | #define DISABLE false 11 | #define ENABLE true 12 | 13 | void __attribute__((__interrupt__, no_auto_psv)) _CNInterrupt(void) { 14 | 15 | if ((((PORTB >> 10) & GetLA_TRIGGER_CHANNEL()) > 0) == GetLA_TRIGGER_STATE()) { 16 | INTERRUPT_LA1PinChange(DISABLE); 17 | INTERRUPT_LA2PinChange(DISABLE); 18 | INTERRUPT_LA3PinChange(DISABLE); 19 | INTERRUPT_LA4PinChange(DISABLE); 20 | INTERRUPT_DisablePinChangeInterrupts(); 21 | 22 | TMR2_Start(); 23 | SetDefaultDIGITAL_STATES(); 24 | IC_PARAMS_ManualTriggerAll(); 25 | SetDefaultDIGITAL_STATES_ERROR(); 26 | } 27 | INTERRUPT_ClearPinChangeInterruptsFlag(); 28 | } 29 | 30 | void __attribute__((__interrupt__, no_auto_psv)) _INT2Interrupt(void) { 31 | 32 | SetDefaultDIGITAL_STATES(); 33 | IC_PARAMS_ManualTriggerAll(); 34 | SetDefaultDIGITAL_STATES_ERROR(); 35 | 36 | INTERRUPT_ClearExternalInterrupt2Flag(); 37 | INTERRUPT_DisableExternalInterrupt2(); 38 | } 39 | 40 | void INTERRUPT_Initialize(void) { 41 | // ADI: ADC1 Convert Done 42 | // Priority: 1 43 | IPC3bits.AD1IP = 1; 44 | // MICI: I2C2 Master Events 45 | // Priority: 1 46 | IPC12bits.MI2C2IP = 1; 47 | // SICI: I2C2 Slave Events 48 | // Priority: 1 49 | IPC12bits.SI2C2IP = 1; 50 | 51 | _INT1IF = 0; 52 | _INT1IE = 0; 53 | 54 | _U1RXIF = 0; 55 | _U1RXIE = 0; 56 | 57 | _U2RXIF = 0; 58 | _U2RXIE = 0; 59 | } 60 | -------------------------------------------------------------------------------- /src/registers/system/interrupt_manager.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTERRUPT_MANAGER_H 2 | #define _INTERRUPT_MANAGER_H 3 | 4 | /** 5 | @Summary 6 | Initializes the interrupt priorities of the PIC24EP256GP204 7 | 8 | @Description 9 | This routine sets the interrupt priorities of the modules that have been configured 10 | for the PIC24EP256GP204 11 | 12 | @Preconditions 13 | None. 14 | 15 | @Returns 16 | None. 17 | 18 | @Param 19 | None. 20 | 21 | @Example 22 | 23 | void SYSTEM_Initialize(void) 24 | { 25 | // Other initializers are called from this function 26 | INTERRUPT_Initialize (); 27 | } 28 | 29 | 30 | */ 31 | void INTERRUPT_Initialize(void); 32 | 33 | /** 34 | @Summary 35 | Enables global interrupts of the PIC24EP256GP204 36 | 37 | @Description 38 | This routine enables the global interrupt bit for the PIC24EP256GP204 39 | 40 | @Preconditions 41 | None. 42 | 43 | @Returns 44 | None. 45 | 46 | @Param 47 | None. 48 | 49 | @Example 50 | 51 | void SYSTEM_Initialize(void) 52 | { 53 | // Other initializers are called from this function 54 | INTERRUPT_GlobalEnable (); 55 | } 56 | 57 | 58 | */ 59 | inline static void INTERRUPT_GlobalEnable(void) { 60 | __builtin_enable_interrupts(); 61 | } 62 | 63 | /** 64 | @Summary 65 | Disables global interrupts of the PIC24EP256GP204 66 | 67 | @Description 68 | This routine disables the global interrupt bit for the PIC24EP256GP204 69 | 70 | @Preconditions 71 | None. 72 | 73 | @Returns 74 | None. 75 | 76 | @Param 77 | None. 78 | 79 | @Example 80 | 81 | void SYSTEM_Initialize(void) 82 | { 83 | // Other initializers are called from this function 84 | INTERRUPT_GlobalDisable (); 85 | } 86 | 87 | 88 | */ 89 | inline static void INTERRUPT_GlobalDisable(void) { 90 | __builtin_disable_interrupts(); 91 | } 92 | 93 | /** 94 | @Summary 95 | Returns the interrupt vector number of the interrupt which is pending. 96 | 97 | @Description 98 | This routine returns the interrupt vector number of the interrupt which is pending. 99 | 100 | @Preconditions 101 | None. 102 | 103 | @Returns 104 | None. 105 | 106 | @Param 107 | None. 108 | 109 | @Example 110 | 111 | uint16_t ivrNum; 112 | ivrNum = INTERRUPT_VectorNumberGet(); 113 | 114 | 115 | */ 116 | inline static uint16_t INTERRUPT_VectorNumberGet(void) { 117 | return _VECNUM; 118 | } 119 | 120 | inline static void INTERRUPT_ClearPinChangeInterruptsFlag(void) { 121 | IFS1bits.CNIF = 0; 122 | } 123 | 124 | inline static void INTERRUPT_EnablePinChangeInterrupts(void) { 125 | IEC1bits.CNIE = 1; 126 | } 127 | 128 | inline static void INTERRUPT_DisablePinChangeInterrupts(void) { 129 | IEC1bits.CNIE = 0; 130 | } 131 | 132 | inline static void INTERRUPT_EnableExternalInterrupt2(void) { 133 | IEC1bits.INT2IE = 1; 134 | } 135 | 136 | inline static void INTERRUPT_DisableExternalInterrupt2(void) { 137 | IEC1bits.INT2IE = 0; 138 | } 139 | 140 | inline static void INTERRUPT_ClearExternalInterrupt2Flag(void) { 141 | IFS1bits.INT2IF = 0; 142 | } 143 | 144 | inline static void INTERRUPT_LA1PinChange(bool state) { 145 | _CNIEB10 = state ? 1 : 0; 146 | } 147 | 148 | inline static void INTERRUPT_LA2PinChange(bool state) { 149 | _CNIEB11 = state ? 1 : 0; 150 | } 151 | 152 | inline static void INTERRUPT_LA3PinChange(bool state) { 153 | _CNIEB12 = state ? 1 : 0; 154 | } 155 | 156 | inline static void INTERRUPT_LA4PinChange(bool state) { 157 | _CNIEB13 = state ? 1 : 0; 158 | } 159 | 160 | #endif 161 | -------------------------------------------------------------------------------- /src/registers/system/pin_manager.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "pin_manager.h" 4 | #include "../../bus/uart/uart.h" 5 | 6 | uint8_t PIN_MANAGER_DIGITAL_PINS[] = { 7 | PIN_MANAGER_DIGITAL_PINS_LA1, 8 | PIN_MANAGER_DIGITAL_PINS_LA2, 9 | PIN_MANAGER_DIGITAL_PINS_LA3, 10 | PIN_MANAGER_DIGITAL_PINS_LA4, 11 | PIN_MANAGER_DIGITAL_PINS_COMP4, 12 | PIN_MANAGER_DIGITAL_PINS_SPI_CS, 13 | PIN_MANAGER_DIGITAL_PINS_FREQ 14 | }; 15 | 16 | void PIN_MANAGER_Initialize(void) { 17 | 18 | // PTG WatchDogTimer is disabled 19 | PTGCONbits.PTGWDT = 0; 20 | // Enable WatchDogTimer 21 | RCONbits.SWDTEN = 1; 22 | 23 | /**************************************************************************** 24 | * Setting the Output Latch SFR(s) 25 | ***************************************************************************/ 26 | LATA = 0x0000; 27 | LATB = 0x0080; 28 | LATC = 0x0000; 29 | 30 | UART1_TX_SetHigh(); 31 | UART2_TX_SetHigh(); 32 | 33 | CS_MUX1_SetHigh(); 34 | CS_MUX2_SetHigh(); 35 | CS_MUX3_SetHigh(); 36 | CS_V5_SetHigh(); 37 | 38 | BOOT_SetHigh(); 39 | 40 | /**************************************************************************** 41 | * Setting the GPIO Direction SFR(s) 42 | ***************************************************************************/ 43 | TRISA = 0x0797; 44 | TRISB = 0xFD7F; 45 | TRISC = 0x03F7; 46 | 47 | I2C_SCL_SetDigitalInput(); 48 | I2C_SDA_SetDigitalInput(); 49 | 50 | UART1_TX_SetDigitalOutput(); 51 | UART1_RX_SetDigitalInput(); 52 | UART2_TX_SetDigitalOutput(); 53 | UART2_RX_SetDigitalInput(); 54 | 55 | BOOT_SetDigitalOutput(); // Bootloader enable pin 56 | 57 | CS_MUX1_SetDigitalOutput(); 58 | CS_MUX2_SetDigitalOutput(); 59 | CS_MUX3_SetDigitalOutput(); 60 | CS_V5_SetDigitalOutput(); 61 | 62 | OSC_CH1_SetDigitalInput(); // CH1 63 | OSC_CH2_SetDigitalInput(); // CH2 64 | OSC_CH3_SetDigitalInput(); // CH3 65 | OSC_MIC_SetDigitalInput(); // MIC 66 | 67 | LA1_SetDigitalInput(); // LA1_ 68 | LA2_SetDigitalInput(); // LA2_ 69 | LA3_SetDigitalInput(); // LA3_ 70 | LA4_SetDigitalInput(); // LA4_ 71 | 72 | SQR1_SetDigitalOutput(); // SQR1_ 73 | SQR2_SetDigitalOutput(); // SQR2_ 74 | SQR3_SetDigitalOutput(); // SQR3_ 75 | SQR4_SetDigitalOutput(); // SQR4_ 76 | 77 | FQY_SetDigitalInput(); // Pulse counter 78 | VOL_SetDigitalInput(); // Voltage 79 | RES_SetDigitalInput(); // Resistance 80 | CAP_IN_SetDigitalInput(); // Capacitor read pin 81 | CAP_OUT_SetDigitalInput(); // Capacitor charge pin 82 | 83 | SDO1_SetDigitalOutput(); 84 | SCK1_SetDigitalOutput(); 85 | SDI1_SetDigitalInput(); 86 | 87 | LED_SetDigitalOutput(); // Status LED 88 | RGB_LED_SetDigitalOutput(); // WS2812 RGB Led 89 | 90 | /**************************************************************************** 91 | * Setting the Weak Pull Up and Weak Pull Down SFR(s) 92 | ***************************************************************************/ 93 | CNPDA = 0x0000; 94 | CNPDB = 0x0000; 95 | CNPDC = 0x0000; 96 | CNPUA = 0x0000; 97 | CNPUB = 0x0000; 98 | CNPUC = 0x0000; 99 | 100 | /**************************************************************************** 101 | * Setting the Open Drain SFR(s) 102 | ***************************************************************************/ 103 | ODCA = 0x0000; 104 | ODCB = 0x0000; 105 | ODCC = 0x0000; 106 | 107 | /**************************************************************************** 108 | * Setting the Analog/Digital Configuration SFR(s) 109 | ***************************************************************************/ 110 | ANSELA = 0x0000; 111 | ANSELB = 0x0000; 112 | ANSELC = 0x0000; 113 | 114 | VOL_SetAnalog(); 115 | RES_SetAnalog(); 116 | CAP_IN_SetAnalog(); 117 | 118 | OSC_CH1_SetAnalog(); 119 | OSC_CH2_SetAnalog(); 120 | OSC_CH3_SetAnalog(); 121 | OSC_MIC_SetAnalog(); 122 | 123 | /**************************************************************************** 124 | * Assign pin mappings 125 | ***************************************************************************/ 126 | RPOR2bits.RP39R = RPN_U1TX_PORT; //RB7->UART1:U1TX 127 | RPINR18bits.U1RXR = RPI_RP40; //RB8->UART1:U1RX 128 | RPOR1bits.RP37R = RPN_U2TX_PORT; // RB5->UART2:U2TX 129 | RPINR19bits.U2RXR = RPI_RP38; // RB6->UART2:U2RX 130 | 131 | LED_SetHigh(); 132 | } 133 | 134 | response_t PIN_MANAGER_SetWavePinState(void) { 135 | 136 | uint8_t pin_state = UART1_Read(); 137 | 138 | if (pin_state & 0b00010000) { 139 | RPOR5bits.RP54R = RPN_DEFAULT_PORT; // SQ1: C6 140 | } 141 | if (pin_state & 0b00100000) { 142 | RPOR5bits.RP55R = RPN_DEFAULT_PORT; // SQ2: C7 143 | } 144 | if (pin_state & 0b01000000) { 145 | RPOR6bits.RP56R = RPN_DEFAULT_PORT; // SQ3: C8 146 | } 147 | if (pin_state & 0b10000000) { 148 | RPOR6bits.RP57R = RPN_DEFAULT_PORT; // SQ4: C9 149 | } 150 | 151 | // Clear C6-C9 bits using MSBs [XXXX_....] 152 | LATC &= ~((pin_state & 0x00F0) << 2); 153 | // Set C6-C9 bits using LSBs [...._XXXX] 154 | LATC |= ((pin_state & 0x000F) << 6); 155 | 156 | return SUCCESS; 157 | } 158 | 159 | response_t PIN_MANAGER_GetLAPinState(void) { 160 | 161 | uint16_t la_pin_state = (PORTB >> 10) & 0xF; 162 | 163 | UART1_WriteInt(la_pin_state); 164 | 165 | return SUCCESS; 166 | } 167 | -------------------------------------------------------------------------------- /src/registers/system/system.c: -------------------------------------------------------------------------------- 1 | #pragma config ICS = PGD2 //ICD Communication Channel Select bits->Communicate on PGEC2 and PGED2 2 | #pragma config JTAGEN = OFF //JTAG Enable bit->JTAG is disabled 3 | 4 | // FPOR 5 | #pragma config ALTI2C1 = OFF //Alternate I2C1 pins->I2C1 mapped to SDA1/SCL1 pins 6 | #pragma config ALTI2C2 = OFF //Alternate I2C2 pins->I2C2 mapped to SDA2/SCL2 pins 7 | #pragma config WDTWIN = WIN75 //Watchdog Window Select bits->WDT Window is 25% of WDT period 8 | 9 | // FWDT 10 | #pragma config WDTPOST = PS512 //Watchdog Timer Postscaler bits->1:32768 11 | #pragma config WDTPRE = PR128 //Watchdog Timer Prescaler bit->1:128 12 | #pragma config PLLKEN = ON //PLL Lock Enable bit->Clock switch to PLL source will wait until the PLL lock signal is valid. 13 | #pragma config WINDIS = OFF //Watchdog Timer Window Enable bit->Watchdog Timer in Non-Window mode 14 | #pragma config FWDTEN = OFF //Watchdog Timer Enable bit->Watchdog timer enabled/disabled by user software 15 | 16 | // FOSC 17 | #pragma config POSCMD = HS //Primary Oscillator Mode Select bits->HS Crystal Oscillator Mode 18 | #pragma config OSCIOFNC = OFF //OSC2 Pin Function bit->OSC2 is clock output 19 | #pragma config IOL1WAY = OFF //Peripheral pin select configuration->Allow multiple reconfigurations 20 | #pragma config FCKSM = CSECMD //Clock Switching Mode bits->Clock switching is enabled,Fail-safe Clock Monitor is disabled 21 | 22 | // FOSCSEL 23 | #pragma config FNOSC = FRC //Oscillator Source Selection->FRC 24 | #pragma config IESO = OFF //Two-speed Oscillator Start-up Enable bit->Start up with user-selected oscillator source 25 | 26 | // FGS 27 | #pragma config GWRP = OFF //General Segment Write-Protect bit->General Segment may be written 28 | #pragma config GCP = OFF //General Segment Code-Protect bit->General Segment Code protect is Disabled 29 | 30 | #include "pin_manager.h" 31 | #include "clock.h" 32 | #include "system.h" 33 | #include "system_types.h" 34 | #include "../memory/dma.h" 35 | #include "../converters/adc1.h" 36 | #include "../../bus/i2c/i2c.h" 37 | #include "../../bus/uart/uart.h" 38 | #include "../timers/tmr1.h" 39 | #include "../timers/tmr2.h" 40 | #include "../timers/tmr3.h" 41 | #include "../timers/tmr4.h" 42 | #include "../timers/tmr5.h" 43 | #include "../comparators/cvr.h" 44 | #include "../comparators/cmp1.h" 45 | #include "../comparators/cmp2.h" 46 | #include "../comparators/cmp3.h" 47 | #include "../comparators/cmp4.h" 48 | #include "../comparators/ic1.h" 49 | #include "../comparators/ic2.h" 50 | #include "../comparators/ic3.h" 51 | #include "../comparators/ic4.h" 52 | #include "../comparators/oc1.h" 53 | #include "../comparators/oc2.h" 54 | #include "../comparators/oc3.h" 55 | #include "../comparators/oc4.h" 56 | #include "../../registers/system/interrupt_manager.h" 57 | #include "../../sdcard/sd_spi.h" 58 | #include "../../sdcard/fatfs/ff.h" 59 | #include "../../helpers/light.h" 60 | 61 | void SYSTEM_Initialize(void) { 62 | 63 | CLOCK_Initialize(); 64 | 65 | PIN_MANAGER_Initialize(); 66 | 67 | SYSTEM_CORCONInitialize(); 68 | 69 | INTERRUPT_Initialize(); 70 | 71 | UART_Initialize(U1SELECT); 72 | UART_Initialize(U2SELECT); 73 | 74 | ADC1_Initialize(); 75 | 76 | CMP1_Initialize(); 77 | CMP2_Initialize(); 78 | CMP3_Initialize(); 79 | CMP4_Initialize(); 80 | 81 | TMR1_Initialize(); 82 | TMR2_Initialize(); 83 | TMR3_Initialize(); 84 | TMR4_Initialize(); 85 | TMR5_Initialize(); 86 | 87 | IC1_Initialize(); 88 | IC2_Initialize(); 89 | IC3_Initialize(); 90 | IC4_Initialize(); 91 | 92 | I2C_Initialize(); 93 | 94 | CVR_Initialize(); 95 | 96 | OC1_Initialize(); 97 | OC2_Initialize(); 98 | OC3_Initialize(); 99 | OC4_Initialize(); 100 | 101 | DMA_Initialize(); 102 | 103 | LIGHT_RGB(0, 20, 0); 104 | UART_ClearBuffer(U1SELECT); 105 | } 106 | -------------------------------------------------------------------------------- /src/registers/system/system.h: -------------------------------------------------------------------------------- 1 | #ifndef _XTAL_FREQ 2 | #define _XTAL_FREQ 128000000UL 3 | #endif 4 | 5 | #include "xc.h" 6 | #include "stdint.h" 7 | #include "system_types.h" 8 | 9 | #ifndef SYSTEM_H 10 | #define SYSTEM_H 11 | 12 | /** 13 | * Initializes the CPU core control register. 14 | * @example 15 | * 16 | * SYSTEM_CORCONInitialize(); 17 | * 18 | */ 19 | inline static void SYSTEM_CORCONInitialize() { 20 | CORCON = (CORCON & 0x00F2) | CORCON_MODE_PORVALUES; // POR value 21 | } 22 | 23 | /** 24 | * Sets the CPU core control register operating mode to a value that is decided by the 25 | * SYSTEM_CORCON_MODES argument. 26 | * @param modeValue SYSTEM_CORCON_MODES initialization mode specifier 27 | * @example 28 | * 29 | * SYSTEM_CORCONModeOperatingSet(CORCON_MODE_ENABLEALLSATNORMAL_ROUNDUNBIASED); 30 | * 31 | */ 32 | inline static void SYSTEM_CORCONModeOperatingSet(SYSTEM_CORCON_MODES modeValue) { 33 | CORCON = (CORCON & 0x00F2) | modeValue; 34 | } 35 | 36 | /** 37 | * Sets the value of CPU core control register. 38 | * @param value value that needs to be written to the CPU core control register 39 | * @example 40 | * 41 | * SYSTEM_CORCONRegisterValueSet(0x00E2); 42 | * 43 | */ 44 | inline static void SYSTEM_CORCONRegisterValueSet(uint16_t value) { 45 | CORCON = value; 46 | } 47 | 48 | /** 49 | * Gets the value of CPU core control register. 50 | * @return value of the CPU core control register 51 | * @example 52 | * 53 | * corconSave = SYSTEM_CORCONRegisterValueGet(); 54 | * 55 | */ 56 | inline static uint16_t SYSTEM_CORCONRegisterValueGet(void) { 57 | return CORCON; 58 | } 59 | 60 | /** 61 | * Gets the base address of the DEVID register for the currently selected device 62 | * @return base address of the DEVID register 63 | * @example 64 | * 65 | * uint32_t devIdAddress; 66 | * devIdAddress = SYSTEM_DeviceIdRegisterAddressGet(); 67 | * 68 | */ 69 | inline static uint32_t SYSTEM_DeviceIdRegisterAddressGet(void) { 70 | return __DEVID_BASE; 71 | } 72 | 73 | /** 74 | * @Param 75 | none 76 | * @Returns 77 | none 78 | * @Description 79 | Initializes the device to the default states configured in the 80 | * MCC GUI 81 | * @Example 82 | SYSTEM_Initialize(void); 83 | */ 84 | void SYSTEM_Initialize(void); 85 | #endif /* SYSTEM_H */ 86 | -------------------------------------------------------------------------------- /src/registers/system/watchdog.h: -------------------------------------------------------------------------------- 1 | #ifndef WATCHDOG_H 2 | #define WATCHDOG_H 3 | 4 | #include "system.h" 5 | 6 | /** 7 | Section: Type defines 8 | */ 9 | 10 | /** 11 | * Enables Watch Dog Timer (WDT) using the software bit. 12 | * @example 13 | * 14 | * WATCHDOG_TimerSoftwareEnable(); 15 | * 16 | */ 17 | inline static void WATCHDOG_TimerSoftwareEnable(void) { 18 | RCONbits.SWDTEN = 1; 19 | } 20 | 21 | /** 22 | * Disables Watch Dog Timer (WDT) using the software bit. 23 | * @example 24 | * 25 | * WATCHDOG_TimerSoftwareDisable(); 26 | * 27 | */ 28 | inline static void WATCHDOG_TimerSoftwareDisable(void) { 29 | RCONbits.SWDTEN = 0; 30 | } 31 | 32 | /** 33 | * Clears the Watch Dog Timer (WDT). 34 | * @example 35 | * 36 | * WATCHDOG_TimerClear(); 37 | * 38 | */ 39 | inline static void WATCHDOG_TimerClear(void) { 40 | ClrWdt(); 41 | } 42 | 43 | #endif /* WATCHDOG_H */ 44 | -------------------------------------------------------------------------------- /src/registers/timers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(pslab-firmware.elf PRIVATE 2 | tmr1.c 3 | tmr2.c 4 | tmr3.c 5 | tmr4.c 6 | tmr5.c 7 | ) 8 | 9 | target_include_directories(pslab-firmware.elf 10 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 11 | 12 | -------------------------------------------------------------------------------- /src/registers/timers/timer_params.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMER_PARAMS_H 2 | #define TIMER_PARAMS_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif /* __cplusplus */ 9 | 10 | /** Timer Prescaler Definition 11 | 12 | @Summary 13 | Defines the prescaler setting for timer registers 14 | 15 | @Description 16 | Upon selecting the source for a timer, prescaler defines the number of ticks 17 | required to increment the counter by 1. 18 | 19 | Remarks: 20 | None 21 | */ 22 | typedef enum { 23 | TMR_PRESCALER_1 = 0b00, 24 | TMR_PRESCALER_8 = 0b01, 25 | TMR_PRESCALER_64 = 0b10, 26 | TMR_PRESCALER_256 = 0b11 27 | } TIMER_PARAMS_PRESCALER; 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif /* __cplusplus */ 32 | 33 | #endif /* TIMER_PARAMS_H */ 34 | 35 | -------------------------------------------------------------------------------- /src/registers/timers/tmr1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tmr1.h" 3 | 4 | void TMR1_Initialize(void) { 5 | //TMR1 0; 6 | TMR1 = 0x00; 7 | //Period = 0 s; Frequency = 64000000 Hz; PR1 0; 8 | PR1 = 0x00; 9 | //TCKPS 1:1; TON disabled; TSIDL disabled; TCS FOSC/2; TSYNC disabled; TGATE disabled; 10 | T1CON = 0x0000; 11 | } 12 | 13 | void TMR1_Period16BitSet(uint16_t value) { 14 | /* Update the counter values */ 15 | PR1 = value; 16 | } 17 | 18 | uint16_t TMR1_Period16BitGet(void) { 19 | return (PR1); 20 | } 21 | 22 | void TMR1_Counter16BitSet(uint16_t value) { 23 | /* Update the counter values */ 24 | TMR1 = value; 25 | } 26 | 27 | uint16_t TMR1_Counter16BitGet(void) { 28 | return (TMR1); 29 | } 30 | 31 | void TMR1_Start(void) { 32 | /* Start the Timer */ 33 | T1CONbits.TON = 1; 34 | } 35 | 36 | void TMR1_Stop(void) { 37 | /* Stop the Timer */ 38 | T1CONbits.TON = false; 39 | } 40 | -------------------------------------------------------------------------------- /src/registers/timers/tmr1.h: -------------------------------------------------------------------------------- 1 | #ifndef _TMR1_H 2 | #define _TMR1_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef __cplusplus // Provide C++ Compatibility 9 | extern "C" { 10 | #endif 11 | 12 | /** 13 | @Summary 14 | Initializes hardware and data for the given instance of the TMR module 15 | 16 | @Description 17 | This routine initializes hardware for the instance of the TMR module, 18 | using the hardware initialization given data. It also initializes all 19 | necessary internal data. 20 | 21 | @Param 22 | None. 23 | 24 | @Returns 25 | None 26 | */ 27 | void TMR1_Initialize(void); 28 | 29 | /** 30 | @Summary 31 | Updates 16-bit timer value 32 | 33 | @Description 34 | This routine updates 16-bit timer value 35 | 36 | @Param 37 | None. 38 | 39 | @Returns 40 | None 41 | */ 42 | void TMR1_Period16BitSet(uint16_t value); 43 | 44 | /** 45 | 46 | @Summary 47 | Provides the timer 16-bit period value 48 | 49 | @Description 50 | This routine provides the timer 16-bit period value 51 | 52 | @Param 53 | None. 54 | 55 | @Returns 56 | Timer 16-bit period value 57 | */ 58 | uint16_t TMR1_Period16BitGet(void); 59 | 60 | /** 61 | @Summary 62 | Updates the timer's 16-bit value 63 | 64 | @Description 65 | This routine updates the timer's 16-bit value 66 | 67 | @Param 68 | None. 69 | 70 | @Returns 71 | None 72 | */ 73 | void TMR1_Counter16BitSet(uint16_t value); 74 | 75 | /** 76 | @Summary 77 | Provides 16-bit current counter value 78 | 79 | @Description 80 | This routine provides 16-bit current counter value 81 | 82 | @Param 83 | None. 84 | 85 | @Returns 86 | 16-bit current counter value 87 | */ 88 | uint16_t TMR1_Counter16BitGet(void); 89 | 90 | 91 | /** 92 | @Summary 93 | Starts the TMR 94 | 95 | @Description 96 | This routine starts the TMR 97 | 98 | @Param 99 | None. 100 | 101 | @Returns 102 | None 103 | */ 104 | void TMR1_Start(void); 105 | 106 | /** 107 | @Summary 108 | Stops the TMR 109 | 110 | @Description 111 | This routine stops the TMR 112 | 113 | @Param 114 | None. 115 | 116 | @Returns 117 | None 118 | */ 119 | void TMR1_Stop(void); 120 | 121 | #ifdef __cplusplus // Provide C++ Compatibility 122 | } 123 | #endif 124 | 125 | #endif //_TMR1_H 126 | -------------------------------------------------------------------------------- /src/registers/timers/tmr2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tmr2.h" 3 | 4 | void TMR2_Initialize(void) { 5 | //TMR2 0; 6 | TMR2 = 0x00; 7 | //Period = 0 s; Frequency = 64000000 Hz; PR2 0; 8 | PR2 = 0x00; 9 | //TCKPS 1:1; T32 16 Bit; TON disabled; TSIDL disabled; TCS FOSC/2; TGATE disabled; 10 | T2CON = 0x0000; 11 | } 12 | void TMR2_Period16BitSet(uint16_t value) { 13 | /* Update the counter values */ 14 | PR2 = value; 15 | } 16 | 17 | uint16_t TMR2_Period16BitGet(void) { 18 | return (PR2); 19 | } 20 | 21 | void TMR2_Counter16BitSet(uint16_t value) { 22 | /* Update the counter values */ 23 | TMR2 = value; 24 | } 25 | 26 | uint16_t TMR2_Counter16BitGet(void) { 27 | return (TMR2); 28 | } 29 | 30 | void TMR2_Start(void) { 31 | /* Start the Timer */ 32 | T2CONbits.TON = 1; 33 | } 34 | 35 | void TMR2_Stop(void) { 36 | /* Stop the Timer */ 37 | T2CONbits.TON = false; 38 | } 39 | -------------------------------------------------------------------------------- /src/registers/timers/tmr2.h: -------------------------------------------------------------------------------- 1 | #ifndef _TMR2_H 2 | #define _TMR2_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "timer_params.h" 8 | 9 | #ifdef __cplusplus // Provide C++ Compatibility 10 | extern "C" { 11 | #endif 12 | 13 | /** 14 | @Summary 15 | Initializes hardware and data for the given instance of the TMR module 16 | 17 | @Description 18 | This routine initializes hardware for the instance of the TMR module, 19 | using the hardware initialization given data. It also initializes all 20 | necessary internal data. 21 | 22 | @Param 23 | None. 24 | 25 | @Returns 26 | None 27 | */ 28 | void TMR2_Initialize(void); 29 | 30 | /** 31 | @Summary 32 | Updates 16-bit timer value 33 | 34 | @Description 35 | This routine updates 16-bit timer value 36 | 37 | @Param 38 | None. 39 | 40 | @Returns 41 | None 42 | */ 43 | void TMR2_Period16BitSet(uint16_t value); 44 | 45 | /** 46 | @Summary 47 | Provides the timer 16-bit period value 48 | 49 | @Description 50 | This routine provides the timer 16-bit period value 51 | 52 | @Param 53 | None. 54 | 55 | @Returns 56 | Timer 16-bit period value 57 | */ 58 | uint16_t TMR2_Period16BitGet(void); 59 | 60 | /** 61 | @Summary 62 | Updates the timer's 16-bit value 63 | 64 | @Description 65 | This routine updates the timer's 16-bit value 66 | 67 | @Param 68 | None. 69 | 70 | @Returns 71 | None 72 | */ 73 | void TMR2_Counter16BitSet(uint16_t value); 74 | 75 | /** 76 | @Summary 77 | Provides 16-bit current counter value 78 | 79 | @Description 80 | This routine provides 16-bit current counter value 81 | 82 | @Param 83 | None. 84 | 85 | @Returns 86 | 16-bit current counter value 87 | */ 88 | uint16_t TMR2_Counter16BitGet(void); 89 | 90 | 91 | /** 92 | @Summary 93 | Starts the TMR 94 | 95 | @Description 96 | This routine starts the TMR 97 | 98 | @Param 99 | None. 100 | 101 | @Returns 102 | None 103 | */ 104 | void TMR2_Start(void); 105 | 106 | /** 107 | @Summary 108 | Stops the TMR 109 | 110 | @Description 111 | This routine stops the TMR 112 | 113 | @Param 114 | None. 115 | 116 | @Returns 117 | None 118 | */ 119 | void TMR2_Stop(void); 120 | 121 | /** 122 | @Summary 123 | Combines Timer 2 and Timer 3 modules 124 | 125 | @Description 126 | This routine combines Timer 2 and Timer 3 modules to form 127 | a 32-bit timer module 128 | 129 | @Param 130 | None 131 | 132 | @Returns 133 | None. 134 | */ 135 | inline static void TMR2_CombineWithTimer3(void) { 136 | T2CONbits.T32 = 1; 137 | } 138 | 139 | /** 140 | @Summary 141 | Enable an external pin as timer clock source 142 | 143 | @Description 144 | This routine enables one of the available external pins 145 | to become the clock source for the Timer 2 module 146 | 147 | @Param 148 | None 149 | 150 | @Returns 151 | None. 152 | */ 153 | inline static void TMR2_SetExternalClockAsSource(void) { 154 | T2CONbits.TCS = 1; 155 | } 156 | 157 | /** 158 | @Summary 159 | Sets pre-scaler for Timer 2 module 160 | 161 | @Description 162 | This routine defines the down sample rate for the operating frequency 163 | of Timer 2 module 164 | 165 | @Param 166 | scale: pre-scaler ratio (TIMER_PARAMS_PRESCALER) 167 | 168 | @Returns 169 | None. 170 | */ 171 | inline static void TMR2_SetPrescaler(TIMER_PARAMS_PRESCALER scale) { 172 | T2CONbits.TCKPS = scale; 173 | } 174 | 175 | #ifdef __cplusplus // Provide C++ Compatibility 176 | } 177 | #endif 178 | 179 | #endif //_TMR2_H 180 | -------------------------------------------------------------------------------- /src/registers/timers/tmr3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tmr3.h" 3 | 4 | void TMR3_Initialize(void) { 5 | // Clear timer 3 register 6 | TMR3 = 0x00; 7 | TMR3HLD = 0x00; 8 | //Period = 0 s; Frequency = 64000000 Hz; PR4 0; 9 | PR3 = 0x00; 10 | // Stops timer 11 | T3CONbits.TON = 0; 12 | // Continues module operation in Idle mode 13 | T3CONbits.TSIDL = 0; 14 | // Gated time accumulation is disabled 15 | T3CONbits.TGATE = 0; 16 | // Timer4 Input Clock Pre scale Select bits as 1:1 17 | T3CONbits.TCKPS = 0b00; 18 | // Internal clock (FP) 19 | T3CONbits.TCS = 0; 20 | // Disable interrupts 21 | _T3IE = 0; 22 | _T3IF = 0; 23 | } 24 | 25 | void TMR3_Period16BitSet(uint16_t value) { 26 | /* Update the counter values */ 27 | PR3 = value; 28 | } 29 | 30 | uint16_t TMR3_Period16BitGet(void) { 31 | return (PR3); 32 | } 33 | 34 | void TMR3_Counter16BitSet(uint16_t value) { 35 | /* Update the counter values */ 36 | TMR3 = value; 37 | } 38 | 39 | uint16_t TMR3_Counter16BitGet(void) { 40 | return (TMR3); 41 | } 42 | 43 | uint16_t TMR3_Carry16BitGet(void) { 44 | return TMR3HLD; 45 | } 46 | 47 | void TMR3_Start(void) { 48 | /* Start the Timer */ 49 | T3CONbits.TON = 1; 50 | } 51 | 52 | void TMR3_Stop(void) { 53 | /* Stop the Timer */ 54 | T3CONbits.TON = false; 55 | } 56 | -------------------------------------------------------------------------------- /src/registers/timers/tmr3.h: -------------------------------------------------------------------------------- 1 | #ifndef _TMR3_H 2 | #define _TMR3_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef __cplusplus // Provide C++ Compatibility 9 | extern "C" { 10 | #endif 11 | 12 | /** 13 | @Summary 14 | Initializes hardware and data for the given instance of the TMR module 15 | 16 | @Description 17 | This routine initializes hardware for the instance of the TMR module, 18 | using the hardware initialization given data. It also initializes all 19 | necessary internal data. 20 | 21 | @Param 22 | None. 23 | 24 | @Returns 25 | None 26 | */ 27 | void TMR3_Initialize(void); 28 | 29 | /** 30 | @Summary 31 | Updates 16-bit timer value 32 | 33 | @Description 34 | This routine updates 16-bit timer value 35 | 36 | @Param 37 | None. 38 | 39 | @Returns 40 | None 41 | */ 42 | void TMR3_Period16BitSet(uint16_t value); 43 | 44 | /** 45 | 46 | @Summary 47 | Provides the timer 16-bit period value 48 | 49 | @Description 50 | This routine provides the timer 16-bit period value 51 | 52 | @Param 53 | None. 54 | 55 | @Returns 56 | Timer 16-bit period value 57 | */ 58 | uint16_t TMR3_Period16BitGet(void); 59 | 60 | /** 61 | @Summary 62 | Updates the timer's 16-bit value 63 | 64 | @Description 65 | This routine updates the timer's 16-bit value 66 | 67 | @Param 68 | None. 69 | 70 | @Returns 71 | None 72 | */ 73 | void TMR3_Counter16BitSet(uint16_t value); 74 | 75 | /** 76 | @Summary 77 | Provides 16-bit current counter value 78 | 79 | @Description 80 | This routine provides 16-bit current counter value 81 | 82 | @Param 83 | None. 84 | 85 | @Returns 86 | 16-bit current counter value 87 | */ 88 | uint16_t TMR3_Counter16BitGet(void); 89 | 90 | /** 91 | @Summary 92 | Provides 16-bit hold carry counter value 93 | 94 | @Description 95 | When TMR2 and TMR3 are cascaded to form a single 32-bit timer, 96 | TMR2 hold the Least Significant Word (LSW) and TMR3 holds the 97 | Most Significant Word (MSW). When the LSW is read from TMR2, 98 | the current value of TMR3 is moved to the TMR3HLD register. 99 | The MSW can then be read from TMR3HLD without worrying about 100 | the delay between reads. 101 | 102 | @Param 103 | None. 104 | 105 | @Returns 106 | 16-bit current hold carry value 107 | */ 108 | uint16_t TMR3_Carry16BitGet(void); 109 | 110 | /** 111 | @Summary 112 | Starts the TMR 113 | 114 | @Description 115 | This routine starts the TMR 116 | 117 | @Param 118 | None. 119 | 120 | @Returns 121 | None 122 | */ 123 | void TMR3_Start(void); 124 | 125 | /** 126 | @Summary 127 | Stops the TMR 128 | 129 | @Description 130 | This routine stops the TMR 131 | 132 | @Param 133 | None. 134 | 135 | @Returns 136 | None 137 | */ 138 | void TMR3_Stop(void); 139 | 140 | #ifdef __cplusplus // Provide C++ Compatibility 141 | } 142 | #endif 143 | 144 | #endif //_TMR3_H 145 | -------------------------------------------------------------------------------- /src/registers/timers/tmr4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tmr4.h" 3 | 4 | void TMR4_Initialize(void) { 5 | // Clear timer 4 register 6 | TMR4 = 0x00; 7 | //Period = 0 s; Frequency = 64000000 Hz; PR4 0; 8 | PR4 = 0x00; 9 | // Stops timer 10 | T4CONbits.TON = 0; 11 | // Continues module operation in Idle mode 12 | T4CONbits.TSIDL = 0; 13 | // Gated time accumulation is disabled 14 | T4CONbits.TGATE = 0; 15 | // Timer4 Input Clock Pre scale Select bits as 1:1 16 | T4CONbits.TCKPS = 0b00; 17 | // Timer x and Timer y act as two 16-bit timers 18 | T4CONbits.T32 = 0; 19 | // Internal clock (FP) 20 | T4CONbits.TCS = 0; 21 | } 22 | 23 | void TMR4_Period16BitSet(uint16_t value) { 24 | /* Update the counter values */ 25 | PR4 = value; 26 | } 27 | 28 | uint16_t TMR4_Period16BitGet(void) { 29 | return (PR4); 30 | } 31 | 32 | void TMR4_Counter16BitSet(uint16_t value) { 33 | /* Update the counter values */ 34 | TMR4 = value; 35 | } 36 | 37 | uint16_t TMR4_Counter16BitGet(void) { 38 | return (TMR4); 39 | } 40 | 41 | void TMR4_Start(void) { 42 | /* Start the Timer */ 43 | T4CONbits.TON = 1; 44 | } 45 | 46 | void TMR4_Stop(void) { 47 | /* Stop the Timer */ 48 | T4CONbits.TON = false; 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/registers/timers/tmr4.h: -------------------------------------------------------------------------------- 1 | #ifndef _TMR4_H 2 | #define _TMR4_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef __cplusplus // Provide C++ Compatibility 9 | extern "C" { 10 | #endif 11 | 12 | /** 13 | @Summary 14 | Initializes hardware and data for the given instance of the TMR module 15 | 16 | @Description 17 | This routine initializes hardware for the instance of the TMR module, 18 | using the hardware initialization given data. It also initializes all 19 | necessary internal data. 20 | 21 | @Param 22 | None. 23 | 24 | @Returns 25 | None 26 | */ 27 | void TMR4_Initialize(void); 28 | 29 | /** 30 | @Summary 31 | Updates 16-bit timer value 32 | 33 | @Description 34 | This routine updates 16-bit timer value 35 | 36 | @Param 37 | None. 38 | 39 | @Returns 40 | None 41 | */ 42 | void TMR4_Period16BitSet(uint16_t value); 43 | 44 | /** 45 | @Summary 46 | Provides the timer 16-bit period value 47 | 48 | @Description 49 | This routine provides the timer 16-bit period value 50 | 51 | @Param 52 | None. 53 | 54 | @Returns 55 | Timer 16-bit period value 56 | */ 57 | uint16_t TMR4_Period16BitGet(void); 58 | 59 | /** 60 | @Summary 61 | Updates the timer's 16-bit value 62 | 63 | @Description 64 | This routine updates the timer's 16-bit value 65 | 66 | @Param 67 | None. 68 | 69 | @Returns 70 | None 71 | */ 72 | void TMR4_Counter16BitSet(uint16_t value); 73 | 74 | /** 75 | @Summary 76 | Provides 16-bit current counter value 77 | 78 | @Description 79 | This routine provides 16-bit current counter value 80 | 81 | @Param 82 | None. 83 | 84 | @Returns 85 | 16-bit current counter value 86 | */ 87 | uint16_t TMR4_Counter16BitGet(void); 88 | 89 | 90 | /** 91 | @Summary 92 | Starts the TMR 93 | 94 | @Description 95 | This routine starts the TMR 96 | 97 | @Param 98 | None. 99 | 100 | @Returns 101 | None 102 | */ 103 | void TMR4_Start(void); 104 | 105 | /** 106 | @Summary 107 | Stops the TMR 108 | 109 | @Description 110 | This routine stops the TMR 111 | 112 | @Param 113 | None. 114 | 115 | @Returns 116 | None 117 | */ 118 | void TMR4_Stop(void); 119 | 120 | #ifdef __cplusplus // Provide C++ Compatibility 121 | } 122 | #endif 123 | 124 | #endif //_TMR4_H 125 | -------------------------------------------------------------------------------- /src/registers/timers/tmr5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tmr5.h" 3 | 4 | void TMR5_Initialize(void) { 5 | //TMR5 0; 6 | TMR5 = 0x00; 7 | //Period = 0 s; Frequency = 64000000 Hz; PR5 0; 8 | PR5 = 0x00; 9 | //TCKPS 1:1; TON enabled; TSIDL disabled; TCS FOSC/2; TGATE disabled; 10 | T5CON = 0x0000; 11 | // Disable interrupts 12 | _T5IE = 0; 13 | _T5IF = 0; 14 | } 15 | 16 | void TMR5_Period16BitSet(uint16_t value) { 17 | /* Update the counter values */ 18 | PR5 = value; 19 | } 20 | 21 | uint16_t TMR5_Period16BitGet(void) { 22 | return (PR5); 23 | } 24 | 25 | void TMR5_Counter16BitSet(uint16_t value) { 26 | /* Update the counter values */ 27 | TMR5 = value; 28 | } 29 | 30 | uint16_t TMR5_Counter16BitGet(void) { 31 | return (TMR5); 32 | } 33 | 34 | void TMR5_Start(void) { 35 | /* Start the Timer */ 36 | T5CONbits.TON = 1; 37 | } 38 | 39 | void TMR5_Stop(void) { 40 | /* Stop the Timer */ 41 | T5CONbits.TON = false; 42 | } 43 | 44 | void TMR5_WaitForInterruptEvent(void) { 45 | _T5IF = 0; 46 | while (!_T5IF); 47 | _T5IF = 0; 48 | } 49 | -------------------------------------------------------------------------------- /src/registers/timers/tmr5.h: -------------------------------------------------------------------------------- 1 | #ifndef _TMR5_H 2 | #define _TMR5_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "timer_params.h" 8 | 9 | #ifdef __cplusplus // Provide C++ Compatibility 10 | extern "C" { 11 | #endif 12 | 13 | /** 14 | @Summary 15 | Initializes hardware and data for the given instance of the TMR module 16 | 17 | @Description 18 | This routine initializes hardware for the instance of the TMR module, 19 | using the hardware initialization given data. It also initializes all 20 | necessary internal data. 21 | 22 | @Param 23 | None. 24 | 25 | @Returns 26 | None 27 | */ 28 | void TMR5_Initialize(void); 29 | 30 | /** 31 | @Summary 32 | Updates 16-bit timer value 33 | 34 | @Description 35 | This routine updates 16-bit timer value 36 | 37 | @Param 38 | None. 39 | 40 | @Returns 41 | None 42 | */ 43 | void TMR5_Period16BitSet(uint16_t value); 44 | 45 | /** 46 | 47 | @Summary 48 | Provides the timer 16-bit period value 49 | 50 | @Description 51 | This routine provides the timer 16-bit period value 52 | 53 | @Param 54 | None. 55 | 56 | @Returns 57 | Timer 16-bit period value 58 | */ 59 | 60 | uint16_t TMR5_Period16BitGet(void); 61 | 62 | /** 63 | @Summary 64 | Updates the timer's 16-bit value 65 | 66 | @Description 67 | This routine updates the timer's 16-bit value 68 | 69 | @Param 70 | None. 71 | 72 | @Returns 73 | None 74 | */ 75 | void TMR5_Counter16BitSet(uint16_t value); 76 | 77 | /** 78 | @Summary 79 | Provides 16-bit current counter value 80 | 81 | @Description 82 | This routine provides 16-bit current counter value 83 | 84 | @Param 85 | None. 86 | 87 | @Returns 88 | 16-bit current counter value 89 | */ 90 | uint16_t TMR5_Counter16BitGet(void); 91 | 92 | 93 | /** 94 | @Summary 95 | Starts the TMR 96 | 97 | @Description 98 | This routine starts the TMR 99 | 100 | @Param 101 | None. 102 | 103 | @Returns 104 | None 105 | */ 106 | void TMR5_Start(void); 107 | 108 | /** 109 | @Summary 110 | Stops the TMR 111 | 112 | @Description 113 | This routine stops the TMR 114 | 115 | @Param 116 | None. 117 | 118 | @Returns 119 | None 120 | */ 121 | void TMR5_Stop(void); 122 | 123 | /** 124 | @Summary 125 | Stops the TMR when MCU idles. 126 | 127 | @Description 128 | This routine stops the TMR when the MCU is in idle mode. 129 | 130 | @Param 131 | None. 132 | 133 | @Returns 134 | None 135 | */ 136 | inline static void TMR5_StopWhenIdle(void) { 137 | T5CONbits.TSIDL = 1; 138 | } 139 | 140 | /** 141 | @Summary 142 | Slows down the TMR. 143 | 144 | @Description 145 | This routine sets a prescaler which slows down the TMR by a factor. 146 | 147 | @Param 148 | Pass the desired prescaler from the TIMER_PARAMS_PRESCALER list. 149 | 150 | @Returns 151 | None 152 | */ 153 | inline static void TMR5_SetPrescaler(TIMER_PARAMS_PRESCALER prescaler) { 154 | T5CONbits.TCKPS = prescaler; 155 | } 156 | 157 | /** 158 | @Summary 159 | Disables the TMR interrupt. 160 | 161 | @Description 162 | This routine disables the TMR interrupt. 163 | 164 | @Param 165 | None. 166 | 167 | @Returns 168 | None 169 | */ 170 | inline static void TMR5_InterruptDisable(void) { 171 | IEC1bits.T5IE = 0; 172 | } 173 | 174 | /** 175 | @Summary 176 | Enables the TMR interrupt. 177 | 178 | @Description 179 | This routine enables the TMR interrupt. 180 | 181 | @Param 182 | None. 183 | 184 | @Returns 185 | None 186 | */ 187 | inline static void TMR5_InterruptEnable(void) { 188 | IEC1bits.T5IE = 1; 189 | } 190 | 191 | /** 192 | @Summary 193 | Clears the TMR interrupt flag. 194 | 195 | @Description 196 | This routine clears the TMR interrupt flag. 197 | 198 | @Param 199 | None. 200 | 201 | @Returns 202 | None 203 | */ 204 | inline static void TMR5_InterruptFlagClear(void) { 205 | IFS1bits.T5IF = 0; 206 | } 207 | 208 | inline static void TMR5_PrescalerSet(TIMER_PARAMS_PRESCALER scale) { 209 | T5CONbits.TCKPS = scale; 210 | } 211 | 212 | void TMR5_WaitForInterruptEvent(void); 213 | 214 | #ifdef __cplusplus // Provide C++ Compatibility 215 | } 216 | #endif 217 | 218 | #endif //_TMR5_H 219 | -------------------------------------------------------------------------------- /src/sdcard/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(fatfs) 2 | 3 | target_sources(pslab-firmware.elf PRIVATE 4 | sd_spi.c 5 | sdcard.c 6 | ) 7 | 8 | target_include_directories(pslab-firmware.elf 9 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 10 | 11 | -------------------------------------------------------------------------------- /src/sdcard/fatfs/00readme.txt: -------------------------------------------------------------------------------- 1 | FatFs Module Source Files R0.13b 2 | 3 | 4 | FILES 5 | 6 | 00readme.txt This file. 7 | 00history.txt Revision history. 8 | ff.c FatFs module. 9 | ffconf.h Configuration file of FatFs module. 10 | ff.h Common include file for FatFs and application module. 11 | diskio.h Common include file for FatFs and disk I/O module. 12 | diskio.c An example of glue function to attach existing disk I/O module to FatFs. 13 | integer.h Integer type definitions for FatFs. 14 | ffunicode.c Optional Unicode utility functions. 15 | ffsystem.c An example of optional O/S related functions. 16 | 17 | 18 | Low level disk I/O module is not included in this archive because the FatFs 19 | module is only a generic file system layer and it does not depend on any specific 20 | storage device. You need to provide a low level disk I/O module written to 21 | control the storage device that attached to the target system. 22 | 23 | -------------------------------------------------------------------------------- /src/sdcard/fatfs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | target_sources(pslab-firmware.elf PRIVATE 2 | diskio.c 3 | fatfs_demo.c 4 | ff_time.c 5 | ff.c 6 | ffsystem.c 7 | ffunicode.c 8 | ) 9 | 10 | target_include_directories(pslab-firmware.elf 11 | PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 12 | 13 | -------------------------------------------------------------------------------- /src/sdcard/fatfs/LICENSE.txt: -------------------------------------------------------------------------------- 1 | FatFs License 2 | 3 | FatFs has being developed as a personal project of the author, ChaN. It is free from the code anyone else wrote at current release. Following code block shows a copy of the FatFs license document that heading the source files. 4 | 5 | /*----------------------------------------------------------------------------/ 6 | / FatFs - Generic FAT Filesystem Module Rx.xx / 7 | /-----------------------------------------------------------------------------/ 8 | / 9 | / Copyright (C) 20xx, ChaN, all right reserved. 10 | / 11 | / FatFs module is an open source software. Redistribution and use of FatFs in 12 | / source and binary forms, with or without modification, are permitted provided 13 | / that the following condition is met: 14 | / 15 | / 1. Redistributions of source code must retain the above copyright notice, 16 | / this condition and the following disclaimer. 17 | / 18 | / This software is provided by the copyright holder and contributors "AS IS" 19 | / and any warranties related to this software are DISCLAIMED. 20 | / The copyright owner or contributors be NOT LIABLE for any damages caused 21 | / by use of this software. 22 | /----------------------------------------------------------------------------*/ 23 | 24 | Therefore FatFs license is one of the BSD-style licenses but there is a significant feature. FatFs is mainly intended for embedded systems. In order to extend the usability for commercial products, the redistributions of FatFs in binary form, such as embedded code, binary library and any forms without source code, does not need to include about FatFs in the documentations. This is equivalent to the 1-clause BSD license. Of course FatFs is compatible with the most of open source software licenses including GNU GPL. When you redistribute the FatFs source code with any changes or create a fork, the license can also be changed to GNU GPL, BSD-style license or any open source software license that not conflict with FatFs license. 25 | -------------------------------------------------------------------------------- /src/sdcard/fatfs/diskio.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*/ 2 | /* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */ 3 | /*-----------------------------------------------------------------------*/ 4 | /* If a working storage control module is available, it should be */ 5 | /* attached to the FatFs via a glue function rather than modifying it. */ 6 | /* This is an example of glue functions to attach various existing */ 7 | /* storage control modules to the FatFs module with a defined API. */ 8 | /*-----------------------------------------------------------------------*/ 9 | 10 | #include "diskio.h" /* FatFs lower layer API */ 11 | #include "../sd_spi.h" 12 | 13 | /* Definitions of physical drive number for each drive */ 14 | enum DRIVER_LIST { 15 | DRVA = 0, 16 | }; 17 | 18 | /*-----------------------------------------------------------------------*/ 19 | /* Get Drive Status */ 20 | 21 | /*-----------------------------------------------------------------------*/ 22 | 23 | DSTATUS disk_status( 24 | BYTE pdrv /* Physical drive number to identify the drive */ 25 | ) { 26 | DSTATUS stat = STA_NOINIT; 27 | 28 | switch (pdrv) { 29 | 30 | case DRVA: 31 | if (SD_SPI_IsMediaPresent() == false) { 32 | stat = STA_NODISK; 33 | } else if (SD_SPI_IsMediaInitialized() == true) { 34 | stat &= ~STA_NOINIT; 35 | } 36 | 37 | if (SD_SPI_IsWriteProtected() == true) { 38 | stat |= STA_PROTECT; 39 | } 40 | 41 | break; 42 | 43 | default: 44 | break; 45 | } 46 | return stat; 47 | } 48 | 49 | /*-----------------------------------------------------------------------*/ 50 | /* Initialize a Drive */ 51 | /*-----------------------------------------------------------------------*/ 52 | DSTATUS disk_initialize( 53 | BYTE pdrv /* Physical drive number to identify the drive */ 54 | ) { 55 | DSTATUS stat = STA_NOINIT; 56 | 57 | switch (pdrv) { 58 | case DRVA: 59 | if (SD_SPI_MediaInitialize() == true) { 60 | stat = RES_OK; 61 | } else { 62 | stat = RES_ERROR; 63 | } 64 | break; 65 | default: 66 | break; 67 | } 68 | 69 | return stat; 70 | } 71 | 72 | /*-----------------------------------------------------------------------*/ 73 | /* Read Sector(s) */ 74 | /*-----------------------------------------------------------------------*/ 75 | DRESULT disk_read( 76 | BYTE pdrv, /* Physical drive number to identify the drive */ 77 | BYTE *buff, /* Data buffer to store read data */ 78 | DWORD sector, /* Start sector in LBA */ 79 | UINT count /* Number of sectors to read */ 80 | ) { 81 | DRESULT res = RES_PARERR; 82 | 83 | switch (pdrv) { 84 | case DRVA: 85 | if (SD_SPI_SectorRead(sector, buff, count) == true) { 86 | res = RES_OK; 87 | } else { 88 | res = RES_ERROR; 89 | } 90 | break; 91 | 92 | default: 93 | break; 94 | } 95 | 96 | return res; 97 | } 98 | 99 | /*-----------------------------------------------------------------------*/ 100 | /* Write Sector(s) */ 101 | /*-----------------------------------------------------------------------*/ 102 | DRESULT disk_write( 103 | BYTE pdrv, /* Physical drive number to identify the drive */ 104 | const BYTE *buff, /* Data to be written */ 105 | DWORD sector, /* Start sector in LBA */ 106 | UINT count /* Number of sectors to write */ 107 | ) { 108 | DRESULT res = RES_PARERR; 109 | 110 | switch (pdrv) { 111 | case DRVA: 112 | if (SD_SPI_SectorWrite(sector, buff, count) == true) { 113 | res = RES_OK; 114 | } else { 115 | res = RES_ERROR; 116 | } 117 | break; 118 | 119 | default: 120 | break; 121 | } 122 | 123 | return res; 124 | } 125 | 126 | /*-----------------------------------------------------------------------*/ 127 | /* Miscellaneous Functions */ 128 | /*-----------------------------------------------------------------------*/ 129 | DRESULT disk_ioctl( 130 | BYTE pdrv, /* Physical drive number (0..) */ 131 | BYTE cmd, /* Control code */ 132 | void *buff /* Buffer to send/receive control data */ 133 | ) { 134 | DRESULT res = RES_OK; 135 | 136 | switch (pdrv) { 137 | case DRVA: 138 | return res; 139 | 140 | default: 141 | break; 142 | } 143 | 144 | return RES_PARERR; 145 | } 146 | -------------------------------------------------------------------------------- /src/sdcard/fatfs/diskio.h: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------/ 2 | / Low level disk interface module include file (C)ChaN, 2014 / 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include "integer.h" 13 | 14 | 15 | /* Status of Disk Functions */ 16 | typedef BYTE DSTATUS; 17 | 18 | /* Results of Disk Functions */ 19 | typedef enum { 20 | RES_OK = 0, /* 0: Successful */ 21 | RES_ERROR, /* 1: R/W Error */ 22 | RES_WRPRT, /* 2: Write Protected */ 23 | RES_NOTRDY, /* 3: Not Ready */ 24 | RES_PARERR /* 4: Invalid Parameter */ 25 | } DRESULT; 26 | 27 | 28 | /*---------------------------------------*/ 29 | /* Prototypes for disk control functions */ 30 | 31 | 32 | DSTATUS disk_initialize (BYTE pdrv); 33 | DSTATUS disk_status (BYTE pdrv); 34 | DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); 35 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); 36 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); 37 | 38 | 39 | /* Disk Status Bits (DSTATUS) */ 40 | 41 | #define STA_NOINIT 0x01 /* Drive not initialized */ 42 | #define STA_NODISK 0x02 /* No medium in the drive */ 43 | #define STA_PROTECT 0x04 /* Write protected */ 44 | 45 | 46 | /* Command code for disk_ioctrl function */ 47 | 48 | /* Generic command (Used by FatFs) */ 49 | #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ 50 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ 51 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ 52 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ 53 | #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ 54 | 55 | /* Generic command (Not used by FatFs) */ 56 | #define CTRL_POWER 5 /* Get/Set power status */ 57 | #define CTRL_LOCK 6 /* Lock/Unlock media removal */ 58 | #define CTRL_EJECT 7 /* Eject media */ 59 | #define CTRL_FORMAT 8 /* Create physical format on the media */ 60 | 61 | /* MMC/SDC specific ioctl command */ 62 | #define MMC_GET_TYPE 10 /* Get card type */ 63 | #define MMC_GET_CSD 11 /* Get CSD */ 64 | #define MMC_GET_CID 12 /* Get CID */ 65 | #define MMC_GET_OCR 13 /* Get OCR */ 66 | #define MMC_GET_SDSTAT 14 /* Get SD status */ 67 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */ 68 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ 69 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ 70 | 71 | /* ATA/CF specific ioctl command */ 72 | #define ATA_GET_REV 20 /* Get F/W revision */ 73 | #define ATA_GET_MODEL 21 /* Get model name */ 74 | #define ATA_GET_SN 22 /* Get serial number */ 75 | 76 | #ifdef __cplusplus 77 | } 78 | #endif 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /src/sdcard/fatfs/fatfs_demo.c: -------------------------------------------------------------------------------- 1 | #include "ff.h" 2 | #include "../sd_spi.h" 3 | 4 | static FATFS drive; 5 | static FIL file; 6 | 7 | void FatFsDemo_Tasks(void) { 8 | UINT actualLength; 9 | char data[] = "Hello World!"; 10 | if (SD_SPI_IsMediaPresent() == false) { 11 | return; 12 | } 13 | 14 | if (f_mount(&drive, "0:", 1) == FR_OK) { 15 | if (f_open(&file, "HELLO.TXT", FA_WRITE | FA_CREATE_NEW) == FR_OK) { 16 | f_write(&file, data, sizeof (data) - 1, &actualLength); 17 | f_close(&file); 18 | } 19 | 20 | f_mount(0, "0:", 0); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/sdcard/fatfs/fatfs_demo.h: -------------------------------------------------------------------------------- 1 | /* 2 | (c) 2016 Microchip Technology Inc. and its subsidiaries. You may use this 3 | software and any derivatives exclusively with Microchip products. 4 | 5 | THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER 6 | EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED 7 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A 8 | PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION 9 | WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION. 10 | 11 | IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, 12 | INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND 13 | WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS 14 | BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE 15 | FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN 16 | ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, 17 | THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. 18 | 19 | MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE 20 | TERMS. 21 | */ 22 | #ifndef FATFS_DEMO_H 23 | #define FATFS_DEMO_H 24 | 25 | void FatFsDemo_Tasks(void); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/sdcard/fatfs/ff_time.c: -------------------------------------------------------------------------------- 1 | /* 2 | (c) 2016 Microchip Technology Inc. and its subsidiaries. You may use this 3 | software and any derivatives exclusively with Microchip products. 4 | 5 | THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER 6 | EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED 7 | WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A 8 | PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION 9 | WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION. 10 | 11 | IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, 12 | INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND 13 | WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS 14 | BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE 15 | FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN 16 | ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, 17 | THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. 18 | 19 | MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE 20 | TERMS. 21 | */ 22 | 23 | /* FAT file timestamps are defined as a 32-bit value with bits corresponding to 24 | each of the date/time fields: 25 | 26 | YYYYYYYMMMMDDDDDhhhhhmmmmmmsssss 27 | 28 | bits[31-25] = YYYYYYY = Year (number of years since 1980). Max value allowed 29 | is 199 (year 2099). 30 | 0b0000000 = 1980 31 | 0b0000001 = 1981 32 | 0b0000010 = 1982 33 | ... 34 | 0b1110110 = 2098 35 | 0b1110111 = 2099 36 | 37 | bits[24-21] = MMMM = Month (1-12), 0 is not allowed. 38 | 0b0001 = January 39 | 0b0010 = February 40 | ... 41 | 0b1011 = November 42 | 0b1100 = December 43 | 44 | bits[20-16] = DDDDD = Day (1-31), 0 is not allowed. 45 | 0b00001 = 1st of the month 46 | 0b00010 = 2nd 47 | ... 48 | 0b11110 = 30th 49 | 0b11111 = 31st 50 | 51 | bits[15-11] = hhhhh = hour (0-23) 52 | bits[10-5] = mmmmmm = minutes (0-59) 53 | bits[4-0] = sssss = seconds/2 (0-29) 54 | 0b00000 = 0 seconds 55 | 0b00001 = 2 seconds 56 | ... 57 | 0b11100 = 56 seconds 58 | 0b11101 = 58 seconds 59 | */ 60 | 61 | #include "ff.h" 62 | #include 63 | #include 64 | #include "../../helpers/rtc.h" 65 | 66 | DWORD get_fattime (void){ 67 | 68 | uint32_t unix_timestamp = 0; 69 | RTC_GetTime(&unix_timestamp); 70 | struct tm *tm_info; 71 | 72 | time_t timestamp = (time_t) (unix_timestamp); 73 | tm_info = gmtime(×tamp); 74 | 75 | DWORD fatTime; 76 | 77 | fatTime = (tm_info->tm_sec >> 1); 78 | fatTime |= ( ((DWORD)tm_info->tm_min) << 5 ); 79 | fatTime |= ( ((DWORD)tm_info->tm_hour) << 11 ); 80 | fatTime |= ( ((DWORD)tm_info->tm_mday) << 16 ); 81 | fatTime |= ( ((DWORD)tm_info->tm_mon + 1) << 21 ); 82 | fatTime |= ( ((DWORD)(tm_info->tm_year - 80)) << 25 ); 83 | 84 | return fatTime; 85 | } 86 | -------------------------------------------------------------------------------- /src/sdcard/fatfs/ffsystem.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------*/ 2 | /* Sample Code of OS Dependent Functions for FatFs */ 3 | /* (C)ChaN, 2017 */ 4 | /*------------------------------------------------------------------------*/ 5 | 6 | 7 | #include "ff.h" 8 | 9 | 10 | 11 | #if FF_USE_LFN == 3 /* Dynamic memory allocation */ 12 | 13 | /*------------------------------------------------------------------------*/ 14 | /* Allocate a memory block */ 15 | /*------------------------------------------------------------------------*/ 16 | 17 | void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */ 18 | UINT msize /* Number of bytes to allocate */ 19 | ) 20 | { 21 | return malloc(msize); /* Allocate a new memory block with POSIX API */ 22 | } 23 | 24 | 25 | /*------------------------------------------------------------------------*/ 26 | /* Free a memory block */ 27 | /*------------------------------------------------------------------------*/ 28 | 29 | void ff_memfree ( 30 | void* mblock /* Pointer to the memory block to free (nothing to do for null) */ 31 | ) 32 | { 33 | free(mblock); /* Free the memory block with POSIX API */ 34 | } 35 | 36 | #endif 37 | 38 | 39 | 40 | #if FF_FS_REENTRANT /* Mutual exclusion */ 41 | 42 | /*------------------------------------------------------------------------*/ 43 | /* Create a Synchronization Object */ 44 | /*------------------------------------------------------------------------*/ 45 | /* This function is called in f_mount() function to create a new 46 | / synchronization object for the volume, such as semaphore and mutex. 47 | / When a 0 is returned, the f_mount() function fails with FR_INT_ERR. 48 | */ 49 | 50 | //const osMutexDef_t Mutex[FF_VOLUMES]; /* CMSIS-RTOS */ 51 | 52 | 53 | int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ 54 | BYTE vol, /* Corresponding volume (logical drive number) */ 55 | FF_SYNC_t* sobj /* Pointer to return the created sync object */ 56 | ) 57 | { 58 | /* Win32 */ 59 | *sobj = CreateMutex(NULL, FALSE, NULL); 60 | return (int)(*sobj != INVALID_HANDLE_VALUE); 61 | 62 | /* uITRON */ 63 | // T_CSEM csem = {TA_TPRI,1,1}; 64 | // *sobj = acre_sem(&csem); 65 | // return (int)(*sobj > 0); 66 | 67 | /* uC/OS-II */ 68 | // OS_ERR err; 69 | // *sobj = OSMutexCreate(0, &err); 70 | // return (int)(err == OS_NO_ERR); 71 | 72 | /* FreeRTOS */ 73 | // *sobj = xSemaphoreCreateMutex(); 74 | // return (int)(*sobj != NULL); 75 | 76 | /* CMSIS-RTOS */ 77 | // *sobj = osMutexCreate(Mutex + vol); 78 | // return (int)(*sobj != NULL); 79 | } 80 | 81 | 82 | /*------------------------------------------------------------------------*/ 83 | /* Delete a Synchronization Object */ 84 | /*------------------------------------------------------------------------*/ 85 | /* This function is called in f_mount() function to delete a synchronization 86 | / object that created with ff_cre_syncobj() function. When a 0 is returned, 87 | / the f_mount() function fails with FR_INT_ERR. 88 | */ 89 | 90 | int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */ 91 | FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ 92 | ) 93 | { 94 | /* Win32 */ 95 | return (int)CloseHandle(sobj); 96 | 97 | /* uITRON */ 98 | // return (int)(del_sem(sobj) == E_OK); 99 | 100 | /* uC/OS-II */ 101 | // OS_ERR err; 102 | // OSMutexDel(sobj, OS_DEL_ALWAYS, &err); 103 | // return (int)(err == OS_NO_ERR); 104 | 105 | /* FreeRTOS */ 106 | // vSemaphoreDelete(sobj); 107 | // return 1; 108 | 109 | /* CMSIS-RTOS */ 110 | // return (int)(osMutexDelete(sobj) == osOK); 111 | } 112 | 113 | 114 | /*------------------------------------------------------------------------*/ 115 | /* Request Grant to Access the Volume */ 116 | /*------------------------------------------------------------------------*/ 117 | /* This function is called on entering file functions to lock the volume. 118 | / When a 0 is returned, the file function fails with FR_TIMEOUT. 119 | */ 120 | 121 | int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ 122 | FF_SYNC_t sobj /* Sync object to wait */ 123 | ) 124 | { 125 | /* Win32 */ 126 | return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0); 127 | 128 | /* uITRON */ 129 | // return (int)(wai_sem(sobj) == E_OK); 130 | 131 | /* uC/OS-II */ 132 | // OS_ERR err; 133 | // OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); 134 | // return (int)(err == OS_NO_ERR); 135 | 136 | /* FreeRTOS */ 137 | // return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); 138 | 139 | /* CMSIS-RTOS */ 140 | // return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); 141 | } 142 | 143 | 144 | /*------------------------------------------------------------------------*/ 145 | /* Release Grant to Access the Volume */ 146 | /*------------------------------------------------------------------------*/ 147 | /* This function is called on leaving file functions to unlock the volume. 148 | */ 149 | 150 | void ff_rel_grant ( 151 | FF_SYNC_t sobj /* Sync object to be signaled */ 152 | ) 153 | { 154 | /* Win32 */ 155 | ReleaseMutex(sobj); 156 | 157 | /* uITRON */ 158 | // sig_sem(sobj); 159 | 160 | /* uC/OS-II */ 161 | // OSMutexPost(sobj); 162 | 163 | /* FreeRTOS */ 164 | // xSemaphoreGive(sobj); 165 | 166 | /* CMSIS-RTOS */ 167 | // osMutexRelease(sobj); 168 | } 169 | 170 | #endif 171 | 172 | -------------------------------------------------------------------------------- /src/sdcard/fatfs/integer.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------*/ 2 | /* Integer type definitions for FatFs module */ 3 | /*-------------------------------------------*/ 4 | 5 | #ifndef FF_INTEGER 6 | #define FF_INTEGER 7 | 8 | #ifdef _WIN32 /* FatFs development platform */ 9 | 10 | #include 11 | typedef unsigned __int64 QWORD; 12 | 13 | #else /* Embedded platform */ 14 | 15 | /* These types MUST be 16-bit or 32-bit */ 16 | typedef int INT; 17 | typedef unsigned int UINT; 18 | 19 | /* This type MUST be 8-bit */ 20 | typedef unsigned char BYTE; 21 | 22 | /* These types MUST be 16-bit */ 23 | typedef short SHORT; 24 | typedef unsigned short WORD; 25 | typedef unsigned short WCHAR; 26 | 27 | /* These types MUST be 32-bit */ 28 | typedef long LONG; 29 | typedef unsigned long DWORD; 30 | 31 | /* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */ 32 | typedef unsigned long long QWORD; 33 | 34 | #endif 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/sdcard/sdcard.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "../bus/uart/uart.h" 6 | #include "../commands.h" 7 | #include "fatfs/ff.h" 8 | #include "fatfs/ffconf.h" 9 | #include "../helpers/debug.h" 10 | #include "../registers/system/watchdog.h" 11 | 12 | #define SFN_MAX 8 13 | #define SFN_SUFFIX_LEN 4 // Period + at most three chars. 14 | #define BUF_MAX FF_MIN_SS 15 | 16 | static void get_filename(TCHAR* const fn_buf, UINT const size) { 17 | for (UINT i = 0; i < size; ++i) { 18 | if (!(fn_buf[i] = UART1_Read())) { 19 | // Received null-terminator. 20 | return; 21 | } 22 | } 23 | // FatFS handles non-terminated strings gracefully, so no need to do a 24 | // manual check for null-termination. 25 | } 26 | 27 | response_t SDCARD_write_file(void) { 28 | // +1 is null-terminator. 29 | size_t const filename_size = SFN_MAX + SFN_SUFFIX_LEN + 1; 30 | TCHAR filename[filename_size]; 31 | get_filename(filename, filename_size); 32 | BYTE const mode = UART1_Read(); 33 | 34 | FATFS drive; 35 | DEBUG_write_u8(f_mount(&drive, "0:", 1)); 36 | 37 | FIL file; 38 | // Host must wait for f_open before sending data. 39 | UART1_Write(f_open(&file, filename, FA_WRITE | mode)); 40 | 41 | FSIZE_t data_size = UART1_read_u32(); 42 | FSIZE_t bytes_written = 0; 43 | 44 | for ( 45 | FSIZE_t block_size, remaining = data_size; 46 | block_size = remaining > BUF_MAX ? BUF_MAX : remaining, 47 | remaining; 48 | remaining -= block_size 49 | ) { 50 | TCHAR buffer[block_size]; 51 | 52 | for (UINT i = 0; i < block_size; ++i) { 53 | buffer[i] = UART1_Read(); 54 | } 55 | 56 | WATCHDOG_TimerClear(); 57 | UINT written = 0; 58 | // Host must wait for f_write before sending more data. 59 | UART1_Write(f_write(&file, buffer, (UINT)block_size, &written)); 60 | bytes_written += written; 61 | } 62 | 63 | UART1_write_u32(bytes_written); 64 | DEBUG_write_u8(f_close(&file)); 65 | DEBUG_write_u8(f_mount(0, "0:", 0)); 66 | 67 | return DO_NOT_BOTHER; 68 | } 69 | 70 | response_t SDCARD_read_file(void) { 71 | TCHAR filename[SFN_MAX + SFN_SUFFIX_LEN + 1]; // +1 is null-terminator. 72 | get_filename(filename, sizeof filename); 73 | 74 | FATFS drive; 75 | DEBUG_write_u8(f_mount(&drive, "0:", 1)); 76 | 77 | FIL file; 78 | DEBUG_write_u8(f_open(&file, filename, FA_READ)); 79 | 80 | FILINFO info = {0, 0, 0, 0, {0}}; 81 | DEBUG_write_u8(f_stat(filename, &info)); 82 | UART1_write_u32(info.fsize); 83 | FSIZE_t bytes_read = 0; 84 | 85 | for ( 86 | FSIZE_t block_size, remaining = info.fsize; 87 | block_size = remaining > BUF_MAX ? BUF_MAX : remaining, 88 | remaining; 89 | remaining -= block_size 90 | ) { 91 | WATCHDOG_TimerClear(); 92 | UINT read = 0; 93 | TCHAR buffer[block_size]; 94 | f_read(&file, &buffer, (UINT)block_size, &read); 95 | bytes_read += read; 96 | 97 | for (UINT i = 0; i < block_size; ++i) { 98 | UART1_Write(buffer[i]); 99 | } 100 | } 101 | 102 | UART1_write_u32(bytes_read); 103 | DEBUG_write_u8(f_close(&file)); 104 | DEBUG_write_u8(f_mount(0, "0:", 0)); 105 | 106 | return DO_NOT_BOTHER; 107 | } 108 | 109 | response_t SDCARD_get_file_info(void) { 110 | TCHAR filename[SFN_MAX + SFN_SUFFIX_LEN + 1]; // +1 is null-terminator. 111 | get_filename(filename, sizeof filename); 112 | 113 | FATFS drive; 114 | DEBUG_write_u8(f_mount(&drive, "0:", 1)); 115 | 116 | FILINFO info = {0, 0, 0, 0, {0}}; 117 | DEBUG_write_u8(f_stat(filename, &info)); 118 | 119 | UART1_write_u32(info.fsize); 120 | UART1_WriteInt(info.fdate); 121 | UART1_WriteInt(info.ftime); 122 | UART1_Write(info.fattrib); 123 | 124 | DEBUG_write_u8(f_mount(0, "0:", 0)); 125 | 126 | return SUCCESS; 127 | } 128 | -------------------------------------------------------------------------------- /src/sdcard/sdcard.h: -------------------------------------------------------------------------------- 1 | #ifndef _SDCARD_H 2 | #define _SDCARD_H 3 | 4 | #include "../commands.h" 5 | 6 | /** 7 | * @brief Write data to a file on the SD-card. 8 | * 9 | * @details UART transaction order: 10 | * Rx[1-12] filename 11 | * Rx[1] mode 12 | * Tx[1] result_mount 13 | * Tx[1] result_open 14 | * Rx[4] data_size 15 | * loop until entire file written: 16 | * Rx[512] data 17 | * Tx[1] result_write 18 | * Tx[4] total_bytes 19 | * Tx[1] result_close 20 | * Tx[1] result_unmount 21 | * 22 | * @param filename TCHAR[12] 23 | * Null-terminated 8.3 filename. 8.3 filenames are limited to at most 24 | * eight characters (after any directory specifier), followed 25 | * optionally by a filename extension consisting of a period and at 26 | * most three further characters. 27 | * @param mode BYTE 28 | * Access mode. A combination of: 29 | * OPEN_EXISTING = 0x00 30 | * CREATE_NEW = 0x04 31 | * CREATE_ALWAYS = 0x08 32 | * OPEN_ALWAYS = 0x10 33 | * OPEN_APPEND = 0x30 34 | * @param data_size FSIZE_t 35 | * Number of bytes to write to the file. 36 | * @param data TCHAR[512] [repeats until data_size written] 37 | * Data to write to the SD-card. 38 | * 39 | * @return result_open FResult 40 | * @return result_write FResult [repeats once per write] 41 | * @return bytes_written FSIZE_t 42 | * Number of bytes which were actually written to the SD-card. This 43 | * should be equal to `data_size` if all went well. 44 | * 45 | * @return DO_NOT_BOTHER 46 | */ 47 | response_t SDCARD_write_file(void); 48 | 49 | /** 50 | * @brief Read data from a file on the SD-card. 51 | * 52 | * @details UART transaction order: 53 | * Rx[1-12] filename 54 | * Tx[1] result_mount 55 | * Tx[1] result_open 56 | * Tx[1] result_stat 57 | * Tx[4] data_size 58 | * loop until entire file read: 59 | * Tx[512] data 60 | * Tx[4] total_bytes 61 | * Tx[1] result_close 62 | * Tx[1] result_unmount 63 | * 64 | * @param filename TCHAR[12] 65 | * Null-terminated 8.3 filename. 8.3 filenames are limited to at most 66 | * eight characters (after any directory specifier), followed 67 | * optionally by a filename extension consisting of a period and at 68 | * most three further characters. 69 | * @return data_size FSIZE_t 70 | * Size of the file. 71 | * @return data TCHAR[512] [repeats until data_size read] 72 | * Data read from the SD-card. 73 | * @return total_bytes FSIZE_t 74 | * Number of bytes which were actually read from the SD-card. This 75 | * should be equal to `file_size` if all went well. If it is not 76 | * equal to `file_size`, any bytes beyond `bytes_read` are invalid. 77 | * 78 | * @return DO_NOT_BOTHER 79 | */ 80 | response_t SDCARD_read_file(void); 81 | 82 | /** 83 | * @brief Get metadata of file on SD-card. 84 | * 85 | * @details See documentation of FatFS FILINFO. 86 | UART transaction order: 87 | * Rx[1-12] filename 88 | * Tx[1] result_mount 89 | * Tx[1] result_stat 90 | * Tx[4] data_size 91 | * Tx[2] modification_date 92 | * Tx[2] modification_time 93 | * Tx[1] file_attributes 94 | * Tx[1] result_unmount 95 | * 96 | * @return SUCCESS 97 | */ 98 | response_t SDCARD_get_file_info(void); 99 | 100 | #endif // _SDCARD_H 101 | -------------------------------------------------------------------------------- /src/states.c: -------------------------------------------------------------------------------- 1 | #include "registers/system/system.h" 2 | #include "bus/uart/uart.h" 3 | #include "registers/system/watchdog.h" 4 | #include "commands.h" 5 | #include "states.h" 6 | 7 | /** 8 | * @brief Wait for incoming serial traffic. 9 | * @return STATE_STANDBY or STATE_RUNCOMMAND 10 | */ 11 | state_t Standby(void) { 12 | if (UART_IsRxReady(U1SELECT)) { 13 | return STATE_RUNCOMMAND; 14 | } else { 15 | WATCHDOG_TimerClear(); 16 | return STATE_STANDBY; 17 | } 18 | } 19 | 20 | /** 21 | * @brief Receive commands bytes, run command, and send response. 22 | * @return STATE_STANDBY 23 | */ 24 | state_t RunCommand(void) { 25 | command_t primary_cmd = UART1_Read(); 26 | command_t secondary_cmd = UART1_Read(); 27 | 28 | // Sanitize input. 29 | if (primary_cmd > NUM_PRIMARY_CMDS) return STATE_STANDBY; 30 | if (secondary_cmd > num_secondary_cmds[primary_cmd]) return STATE_STANDBY; 31 | 32 | response_t response = cmd_table[primary_cmd][secondary_cmd](); 33 | 34 | if (response) UART1_Write(response); 35 | 36 | return STATE_STANDBY; 37 | } 38 | 39 | state_func_t* const state_table[NUM_STATES] = { 40 | Standby, 41 | RunCommand, 42 | }; 43 | 44 | state_t STATES_RunState(state_t current_state) { 45 | return state_table[current_state](); 46 | }; 47 | -------------------------------------------------------------------------------- /src/states.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file states.h 3 | * @brief Main state machine. 4 | */ 5 | 6 | #ifndef STATES_H 7 | #define STATES_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** 14 | * @brief States. 15 | */ 16 | typedef enum { 17 | STATE_STANDBY, 18 | STATE_RUNCOMMAND, 19 | NUM_STATES 20 | } state_t; 21 | 22 | typedef state_t state_func_t(void); /**< Type for state functions. */ 23 | 24 | /** 25 | * 26 | * @brief Run the state machine. 27 | * @param Current state 28 | * @return Next state 29 | */ 30 | state_t STATES_RunState(state_t current_state); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif /* STATES_H */ 37 | --------------------------------------------------------------------------------