| /* |
| * Copyright 2023 Google LLC |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "hw/top_matcha/sw/autogen/top_matcha.h" |
| #include "sw/device/lib/arch/device.h" |
| #include "sw/device/lib/camera_hm01b0.h" |
| #include "sw/device/lib/dif/dif_cam_ctrl.h" |
| #include "sw/device/lib/dif/dif_isp_wrapper.h" |
| #include "sw/device/lib/dif/dif_rv_plic.h" |
| #include "sw/device/lib/dif/dif_spi_host.h" |
| #include "sw/device/lib/dif/dif_tlul_mailbox.h" |
| #include "sw/device/lib/dif/dif_uart.h" |
| #include "sw/device/lib/runtime/irq.h" |
| #include "sw/device/lib/runtime/print.h" |
| #include "sw/device/lib/spi_display/LCD_Driver.h" |
| #include "sw/device/lib/spi_display/spi_display.h" |
| #include "sw/device/lib/testing/test_framework/check.h" |
| #include "sw/device/lib/testing/test_framework/ottf_test_config.h" |
| #include "sw/device/lib/testing/test_framework/test_util.h" |
| |
| OTTF_DEFINE_TEST_CONFIG(); |
| |
| static spi_display_t spi_display; |
| static dif_cam_ctrl_t cam_ctrl; |
| static dif_uart_t smc_uart; |
| static dif_spi_host_t spi_host2; |
| static dif_isp_wrapper_t isp_wrapper; |
| static dif_tlul_mailbox_t tlul_mailbox; |
| static dif_rv_plic_t plic_smc; |
| |
| // 320x240 RGB565 buffer, contains the pixel data |
| // to be drawn to the display. |
| static uint16_t rgb565_buffer[LCD_WIDTH * LCD_HEIGHT]; |
| static PAINT paint_ctx; |
| |
| static volatile bool isp_frame_done_irq_seen = false; |
| |
| void ottf_external_isr(void) { |
| dif_rv_plic_irq_id_t plic_irq_id; |
| |
| // Clear IRQ from the tlul_mailbox and claim it from the PLIC. |
| CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic_smc, kTopMatchaPlicTargetIbex0Smc, |
| &plic_irq_id)); |
| top_matcha_plic_peripheral_smc_t peripheral_id = |
| top_matcha_plic_interrupt_for_peripheral_smc[plic_irq_id]; |
| |
| switch (peripheral_id) { |
| case kTopMatchaPlicPeripheralCamI2c: { |
| CHECK_DIF_OK(camera_hm01b0_irq_handler(plic_irq_id)); |
| break; |
| } |
| case kTopMatchaPlicPeripheralIspWrapper: { |
| uint32_t mi_mis, isp_mis; |
| CHECK_DIF_OK(dif_isp_wrapper_read_mi_mis(&isp_wrapper, &mi_mis)); |
| CHECK_DIF_OK(dif_isp_wrapper_read_isp_mis(&isp_wrapper, &isp_mis)); |
| CHECK_DIF_OK(dif_isp_wrapper_write_isp_icr(&isp_wrapper, isp_mis)); |
| CHECK_DIF_OK(dif_isp_wrapper_write_mi_icr(&isp_wrapper, mi_mis)); |
| CHECK_DIF_OK(dif_isp_wrapper_irq_acknowledge_all(&isp_wrapper)); |
| |
| if (isp_mis & (1 << 5)) { |
| isp_frame_done_irq_seen = true; |
| } |
| |
| break; |
| } |
| case kTopMatchaPlicPeripheralTlulMailboxSmc: { |
| CHECK_DIF_OK(spi_display_smc_mailbox_irq_handler(&spi_display)); |
| break; |
| } |
| case kTopMatchaPlicPeripheralSpiHost2: { |
| CHECK_DIF_OK(spi_display_spi_irq_handler(&spi_display)); |
| break; |
| } |
| default: |
| LOG_FATAL("Unexpected peripheral_id!"); |
| } |
| |
| CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic_smc, kTopMatchaPlicTargetIbex0Smc, |
| plic_irq_id)); |
| } |
| void _ottf_main(void) { |
| // Config_Init |
| init_uart(TOP_MATCHA_SMC_UART_BASE_ADDR, &smc_uart); |
| LOG_INFO("spi_display_smc"); |
| // Initialize cam_ctrl and ISP. |
| CHECK_DIF_OK(dif_cam_ctrl_init( |
| mmio_region_from_addr(TOP_MATCHA_CAM_CTRL_BASE_ADDR), &cam_ctrl)); |
| CHECK_DIF_OK(dif_isp_wrapper_init( |
| mmio_region_from_addr(TOP_MATCHA_ISP_WRAPPER_BASE_ADDR), &isp_wrapper)); |
| |
| // Configure Mailbox. |
| CHECK_DIF_OK(dif_tlul_mailbox_init( |
| mmio_region_from_addr(TOP_MATCHA_TLUL_MAILBOX_SMC_BASE_ADDR), |
| &tlul_mailbox)); |
| CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled( |
| &tlul_mailbox, kDifTlulMailboxIrqRtirq, kDifToggleEnabled)); |
| CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled( |
| &tlul_mailbox, kDifTlulMailboxIrqWtirq, kDifToggleEnabled)); |
| CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled( |
| &tlul_mailbox, kDifTlulMailboxIrqEirq, kDifToggleEnabled)); |
| |
| CHECK_DIF_OK(dif_rv_plic_init( |
| mmio_region_from_addr(TOP_MATCHA_RV_PLIC_SMC_BASE_ADDR), &plic_smc)); |
| |
| // Configure interrupts for Camera, ISP and mailbox. |
| CHECK_DIF_OK(camera_hm01b0_irq_init(&plic_smc, kTopMatchaPlicTargetIbex0Smc)); |
| CHECK_DIF_OK(dif_rv_plic_irq_set_enabled( |
| &plic_smc, kTopMatchaPlicIrqIdIspWrapperIsp, kTopMatchaPlicTargetIbex0Smc, |
| kDifToggleEnabled)); |
| CHECK_DIF_OK(dif_rv_plic_irq_set_enabled( |
| &plic_smc, kTopMatchaPlicIrqIdIspWrapperMi, kTopMatchaPlicTargetIbex0Smc, |
| kDifToggleEnabled)); |
| CHECK_DIF_OK(dif_rv_plic_irq_set_priority( |
| &plic_smc, kTopMatchaPlicIrqIdIspWrapperIsp, kDifRvPlicMaxPriority)); |
| CHECK_DIF_OK(dif_rv_plic_irq_set_priority( |
| &plic_smc, kTopMatchaPlicIrqIdIspWrapperMi, kDifRvPlicMaxPriority)); |
| CHECK_DIF_OK(dif_rv_plic_irq_set_enabled( |
| &plic_smc, kTopMatchaPlicIrqIdTlulMailboxSmcRtirq, |
| kTopMatchaPlicTargetIbex0Smc, kDifToggleEnabled)); |
| CHECK_DIF_OK(dif_rv_plic_irq_set_priority( |
| &plic_smc, kTopMatchaPlicIrqIdTlulMailboxSmcRtirq, 1)); |
| irq_global_ctrl(true); |
| irq_external_ctrl(true); |
| |
| // Initialize the SPI host and display. |
| CHECK_DIF_OK(dif_spi_host_init( |
| mmio_region_from_addr(TOP_MATCHA_SPI_HOST2_BASE_ADDR), &spi_host2)); |
| dif_spi_host_config_t config = { |
| .spi_clock = kClockFreqSpiDisplayHz, |
| .peripheral_clock_freq_hz = kClockFreqCpuHz, |
| }; |
| CHECK_DIF_OK(dif_spi_host_configure(&spi_host2, config)); |
| CHECK_DIF_OK(dif_spi_host_output_set_enabled(&spi_host2, /*enabled=*/true)); |
| CHECK_DIF_OK(spi_display_init(&spi_display, &spi_host2, &tlul_mailbox)); |
| CHECK_DIF_OK(spi_display_irq_init(&spi_display, &plic_smc, |
| kTopMatchaPlicIrqIdSpiHost2SpiEvent, |
| kTopMatchaPlicTargetIbex0Smc)); |
| |
| // Configure and enable camera. |
| CHECK_DIF_OK(camera_hm01b0_init()); |
| CHECK_DIF_OK(camera_hm01b0_set_default_registers( |
| kCameraHm01b0Resolution320x240, kCameraHm01b0FrameRate1Fps)); |
| CHECK_DIF_OK(dif_isp_wrapper_set_raw_320x240_byp_320x240_en(&isp_wrapper)); |
| CHECK_DIF_OK(dif_cam_ctrl_set_en(&cam_ctrl)); |
| |
| Paint_NewImage(&paint_ctx, LCD_WIDTH, LCD_HEIGHT, ROTATE_0, MIRROR_NONE); |
| while (true) { |
| while (!isp_frame_done_irq_seen) { |
| asm volatile("wfi"); |
| } |
| isp_frame_done_irq_seen = false; |
| |
| for (int i = 0; i < LCD_WIDTH * LCD_HEIGHT; ++i) { |
| uint8_t y = *(((const uint8_t*)TOP_MATCHA_ML_TOP_DMEM_BASE_ADDR) + i); |
| uint16_t rgb565 = |
| ((y >> 3) & 0x1F) << 11 | ((y >> 2) & 0x3F) << 5 | ((y >> 3) & 0x1F); |
| rgb565_buffer[i] = __builtin_bswap16(rgb565); |
| } |
| |
| memset(paint_ctx.Image, 0xF0, sizeof(paint_ctx.Image)); |
| // This is an placeholder string, to demonstrate drawing |
| // something like the output scores from a model. |
| Paint_DrawString_EN(&paint_ctx, 0, 0, "(-127, -127)", &Font16, BLACK, |
| WHITE); |
| for (int i = 0; i < LCD_WIDTH * LCD_HEIGHT; ++i) { |
| if (paint_ctx.Image[i] == 0xF0F0) { |
| continue; |
| } |
| rgb565_buffer[i] = __builtin_bswap16(paint_ctx.Image[i]); |
| } |
| |
| LCD_ClearToBuffer(&spi_display, rgb565_buffer); |
| } |
| |
| while (true) { |
| asm volatile("wfi"); |
| } |
| } |