diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d23841..171daf6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,9 @@ target_sources(${PROJ_NAME}.elf PUBLIC start.S) add_subdirectory(${BASE_DIR}/driver driver) target_link_libraries(${PROJ_NAME}.elf driver) +add_subdirectory(${BASE_DIR}/component component) +target_link_libraries(${PROJ_NAME}.elf component) + add_subdirectory(${BASE_DIR}/CMSIS) target_link_libraries(${PROJ_NAME}.elf cmsis) diff --git a/component/CMakeLists.txt b/component/CMakeLists.txt new file mode 100644 index 0000000..4bb4aa3 --- /dev/null +++ b/component/CMakeLists.txt @@ -0,0 +1,9 @@ +file(GLOB FILELIST +component.c +) +set(TARGET component) +add_library(${TARGET} STATIC ${FILELIST}) + +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/pio_instance pio_instance) + +target_link_libraries(${TARGET} pio_instance) diff --git a/component/component.c b/component/component.c new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/component/component.c @@ -0,0 +1 @@ + diff --git a/component/pio_instance/CMakeLists.txt b/component/pio_instance/CMakeLists.txt new file mode 100644 index 0000000..5a30806 --- /dev/null +++ b/component/pio_instance/CMakeLists.txt @@ -0,0 +1,10 @@ +file(GLOB FILELIST +src/pio_rmii_tx.c +) + +set(TARGET pio_instance) +add_library(${TARGET} STATIC ${FILELIST}) + +target_include_directories(${TARGET} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/inc) +target_include_directories(${TARGET} PUBLIC ${BASE_DIR}/driver/inc) +target_include_directories(${TARGET} PUBLIC ${BASE_DIR}/driver/inc/reg) diff --git a/component/pio_instance/inc/pio_rmii_tx.h b/component/pio_instance/inc/pio_rmii_tx.h new file mode 100644 index 0000000..f9c0575 --- /dev/null +++ b/component/pio_instance/inc/pio_rmii_tx.h @@ -0,0 +1,25 @@ +#ifndef __HARDWARE_PIO_RMII_TX_H__ +#define __HARDWARE_PIO_RMII_TX_H__ + +#include "pio.h" + +struct pio_rmii_tx_s { + uint16_t clkdiv; + uint8_t sm; + uint8_t addr; + uint8_t flag; + uint8_t pin; /* increase order of pin CLK-EN-D0-D1 */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +void pio_rmii_tx_init(struct pio_rmii_tx_s *cfg); +void pio_rmii_write(struct pio_rmii_tx_s *rmii, uint32_t *data, uint32_t length); + +#ifdef __cplusplus +} +#endif + +#endif /* __HARDWARE_PIO_RMII_TX_H__ */ diff --git a/component/pio_instance/src/pio_rmii_tx.c b/component/pio_instance/src/pio_rmii_tx.c new file mode 100644 index 0000000..4c30a84 --- /dev/null +++ b/component/pio_instance/src/pio_rmii_tx.c @@ -0,0 +1,86 @@ +#include "pio_rmii_tx.h" + +void pio_rmii_tx_init(struct pio_rmii_tx_s *rmii) +{ + struct pio_cfg_s cfg; + uint32_t pio = PIO0_BASE + (PIO1_BASE - PIO0_BASE) * (rmii->sm / PIO_SM_COUNT); + uint8_t sm = rmii->sm % PIO_SM_COUNT; + uint8_t addr = rmii->addr; + + cfg.pio_base = pio; /* pio register address base */ + cfg.clkdiv_int = rmii->clkdiv; /* clock divisor of integer part, 1~65535 is available, 0 present 65536 divisor */ + cfg.clkdiv_frac = 0; /* clock divisor of fractional part, (div_frac/256) is actual value */ + cfg.sm = sm; /* state machine identification, 0~3 is available */ + cfg.fifo_join = PIO_FIFO_RX_JOIN_TX; /* tx/ tx fifo join type */ + cfg.wrap_bottom = 0; /* ater reaching wrap_top, execution is wrapped to this address */ + cfg.wrap_top = 14; /* after reaching this address, execution is wrapped to wrap_bottom */ + cfg.mov_status_sel_rx = 0; /* comparison used for the 'MOV x, STATUS' instruction */ + cfg.mov_status_level = 0; /* comparison level for the 'MOV x, STATUS' instruction */ + cfg.thresh_bits_pull = 32; /* number of bits shifted out of TXSR before autopull or conditional pull, 1~31, 0 present 32 */ + cfg.thresh_bits_push = 0; /* number of bits shifted into RXSR before autopush or conditional push, 1~31, 0 present 32 */ + cfg.out_dir_to_right = 1; /* shift OSR direction */ + cfg.in_dir_to_right = 0; /* shift ISR direction */ + cfg.auto_pull = 1; /* pull automatically when the output shift register is emptied */ + cfg.auto_push = 0; /* push automatically when the input shift register is filled */ + cfg.out_sticky = 0; /* continuously assert the most recent OUT/SET to the pins */ + cfg.inline_outen = 0; /* whether use a bit of OUT data as an auxiliary write enable */ + cfg.outen_sel = 0; /* which data bit to use for inline OUT enable */ + cfg.side_optional = 0; /* allow instructions to perform sideset optionally, rather than on every instruction */ + cfg.side_dest_pindir = 0; /* side data is asserted to pin OEs or pin values */ + cfg.pin_side_count = 2; /* the number of delay bits co-opted for side-set, inclusive of the enable bit, if present */ + cfg.pin_side_base = rmii->pin + 0; /* the virtual pin corresponding to SIDESET bit 0, not PIO_PIN_XXX, is absolute pin index */ + cfg.pin_set_count = 4; /* the number of pins asserted by a SET, max of 5 */ + cfg.pin_set_base = rmii->pin + 0; /* the virtual pin corresponding to SET bit 0, not PIO_PIN_XXX, is absolute pin index */ + cfg.pin_out_count = 2; /* the number of pins asserted by an OUT, value of 1 to 31 pins, 0 present 32 */ + cfg.pin_out_base = rmii->pin + 2; /* the virtual pin corresponding to OUT bit 0 , not PIO_PIN_XXX, is absolute pin index*/ + cfg.pin_in_base = 0; /* the virtual pin corresponding to IN bit 0, not PIO_PIN_XXX, is absolute pin index */ + cfg.pin_jmp = 0; /* the pin index to use as condition for 'JMP PIN' instruction */ + + pio_init(&cfg); + /* wait data from user */ + pio_instr_place(pio, addr + 0, pio_instr_JMP(PIO_INSTR_JMP_COND_OSR_NEMPTY, addr + 2, pio_instr_side(0, 0, 2))); + pio_instr_place(pio, addr + 1, pio_instr_JMP(PIO_INSTR_JMP_COND_ALWAYS, addr + 0, pio_instr_side(1, 0, 2))); + /* only 6 byte preamble need auto send, 6 * 8 / 2 - 1 = 23 */ + pio_instr_place(pio, addr + 2, pio_instr_SET(PIO_INSTR_SET_DEST_X, 23, pio_instr_side(1, 0, 2))); + /* preamble */ + pio_instr_place(pio, addr + 3, pio_instr_SET(PIO_INSTR_SET_DEST_PINS, 0b0110, pio_instr_side(2, 0, 2))); + pio_instr_place(pio, addr + 4, pio_instr_JMP(PIO_INSTR_JMP_COND_X_WITH_DEC, addr + 3, pio_instr_side(3, 0, 2))); + /* output 2 bits data every clock */ + pio_instr_place(pio, addr + 5, pio_instr_OUT(PIO_INSTR_OUT_DEST_PINS, 2, pio_instr_side(2, 0, 2))); + pio_instr_place(pio, addr + 6, pio_instr_JMP(PIO_INSTR_JMP_COND_OSR_NEMPTY, addr + 5, pio_instr_side(3, 0, 2))); + /* force data pin to low level when idle */ + pio_instr_place(pio, addr + 7, pio_instr_SET(PIO_INSTR_SET_DEST_PINS, 0, pio_instr_side(0, 0, 2))); + /* inter packet gap, 0.96us */ + pio_instr_place(pio, addr + 8, pio_instr_SET(PIO_INSTR_SET_DEST_X, 2, pio_instr_side(1, 0, 2))); + pio_instr_place(pio, addr + 9, pio_instr_SET(PIO_INSTR_SET_DEST_Y, 22, pio_instr_side(0, 0, 2))); + pio_instr_place(pio, addr + 10, pio_instr_MOV(PIO_INSTR_MOV_DEST_Y, PIO_INSTR_MOV_SRC_Y, PIO_INSTR_MOV_OP_NONE, pio_instr_side(1, 0, 2))); /* nop */ + pio_instr_place(pio, addr + 11, pio_instr_JMP(PIO_INSTR_JMP_COND_Y_WITH_DEC, addr + 10, pio_instr_side(0, 0, 2))); + pio_instr_place(pio, addr + 12, pio_instr_JMP(PIO_INSTR_JMP_COND_X_WITH_DEC, addr + 9, pio_instr_side(1, 0, 2))); + /* packet complete because of empty TX_FIFO, set a flag to inform user */ + pio_instr_place(pio, addr + 13, pio_instr_IRQ(PIO_INSTR_IRQ_OP_RAISE, PIO_INSTR_IRQ_WAIT_DISABLE, rmii->flag, pio_instr_side(0, 0, 2))); + pio_instr_place(pio, addr + 14, pio_instr_JMP(PIO_INSTR_JMP_COND_ALWAYS, addr + 0, pio_instr_side(1, 0, 2))); + + pio_instr_insert(pio, sm, pio_instr_SET(PIO_INSTR_SET_DEST_PINDIRS, 0xF, pio_instr_side(0, 0, 2))); + while (!pio_instr_is_complete(pio, sm)); + pio_instr_insert(pio, sm, pio_instr_JMP(PIO_INSTR_JMP_COND_ALWAYS, addr + 0, pio_instr_side(0, 0, 2))); + while (!pio_instr_is_complete(pio, sm)); + pio_enable(pio, sm); +} + +void pio_rmii_write(struct pio_rmii_tx_s *rmii, uint32_t *data, uint32_t length) +{ + uint32_t pio, idx, status; + uint8_t sm; + + pio = PIO0_BASE + (PIO1_BASE - PIO0_BASE) * (rmii->sm / PIO_SM_COUNT); + sm = rmii->sm % PIO_SM_COUNT; + + idx = 0; + while (idx < length) { + status = pio_fifo_get_status(pio, sm); + status &= (PIO_FIFO_STATUS_SM0_TX_FULL << sm); + if (!status) { + pio_fifo_write(pio, sm, data[idx++]); + } + } +}