From 2f2b5df1fd097799cd1441c109a9039ce3bfab3f Mon Sep 17 00:00:00 2001 From: Adam Greenwood-Byrne Date: Sun, 7 Nov 2021 19:53:58 +0000 Subject: [PATCH] Updated docs --- part14-spi-ethernet/README.md | 36 ++++++++++++++++++++++++++++++++++ part15-tcpip/include/spi.h | 1 - part15-tcpip/kernel/irq.c | 31 ----------------------------- part15-tcpip/kernel/irqentry.S | 6 +++++- 4 files changed, 41 insertions(+), 33 deletions(-) diff --git a/part14-spi-ethernet/README.md b/part14-spi-ethernet/README.md index e575ba2..e866bdc 100644 --- a/part14-spi-ethernet/README.md +++ b/part14-spi-ethernet/README.md @@ -62,3 +62,39 @@ Then, whilst there's either data to write or data to read (and we haven't writte Finally, to be absolutely sure, we clear the TA flag. I've then set up two convenient functions - _spi_send()_ and _spi_recv()_ - which exercise _spi_send_recv(), mainly to make future code more readable. + +The ENC28J60 drivers +-------------------- +Let's now look into the _net/_ subdirectory. + +Both _enc28j60.c_ and _enc28j60.h_ make up the driver code for the ENC28J60 Ethernet module. Whilst we could have laboured for months writing our own driver based on [the module's datasheet](http://ww1.microchip.com/downloads/en/devicedoc/39662c.pdf), I chose to leverage somebody else's hard work instead. It felt like a win that I could effortlessly bring somebody else's good code into my own OS! I did, however, make sure I understood what the code was doing at every turn (optional!). + +Thanks to [this Github repository](https://github.com/wolfgangr/enc28j60) for saving me months of work. I made a very few changes to the code, but nothing worth documenting here. If you're keen to see how little I needed to change, clone the repo and make good use of the `diff` command. + +What I did need to do is write some bridging code between the driver and the RPi4 hardware. Essentially, I'm talking about hooking up our SPI library to the driver - the whole reason for _encspi.c_. + +It defines four functions that the driver requires (well documented in the _enc28j60.h_ file): + +```c +void ENC_SPI_Select(unsigned char truefalse) { + spi_chip_select(!truefalse); // If it's true, select 0 (the ENC), if false, select 1 (i.e. deselect the ENC) +} + +void ENC_SPI_SendBuf(unsigned char *master2slave, unsigned char *slave2master, unsigned short bufferSize) { + spi_chip_select(0); + spi_send_recv(master2slave, slave2master, bufferSize); + spi_chip_select(1); // De-select the ENC +} + +void ENC_SPI_Send(unsigned char command) { + spi_chip_select(0); + spi_send(&command, 1); + spi_chip_select(1); // De-select the ENC +} + +void ENC_SPI_SendWithoutSelection(unsigned char command) { + spi_send(&command, 1); +} +``` + +Perhaps the most confusing aspect is the chip selection. Through a bit of trial & error I discovered that when GPIO08 is clear, the device is selected, and when it's set, the device is deselected. If you can explain this to me, I'd love to hear from you - frankly, I was just pleased to get it working, so I moved on! diff --git a/part15-tcpip/include/spi.h b/part15-tcpip/include/spi.h index c5fca8b..bf57e3e 100644 --- a/part15-tcpip/include/spi.h +++ b/part15-tcpip/include/spi.h @@ -2,5 +2,4 @@ void spi_init(); void spi_send_recv(unsigned char *sbuffer, unsigned char *rbuffer, unsigned int size); void spi_send(unsigned char *data, unsigned int size); void spi_recv(unsigned char *data, unsigned int size); -void spi_send_no_selection(unsigned char command); void spi_chip_select(unsigned char chip_select); diff --git a/part15-tcpip/kernel/irq.c b/part15-tcpip/kernel/irq.c index bc2276a..3ab82d1 100644 --- a/part15-tcpip/kernel/irq.c +++ b/part15-tcpip/kernel/irq.c @@ -1,27 +1,4 @@ #include "kernel.h" -#include "../include/fb.h" - -char *entry_error_messages[] = { - "SYNC_INVALID_EL1t", - "IRQ_INVALID_EL1t", - "FIQ_INVALID_EL1t", - "ERROR_INVALID_EL1T", - - "SYNC_INVALID_EL1h", - "IRQ_INVALID_EL1h", - "FIQ_INVALID_EL1h", - "ERROR_INVALID_EL1h", - - "SYNC_INVALID_EL0_64", - "IRQ_INVALID_EL0_64", - "FIQ_INVALID_EL0_64", - "ERROR_INVALID_EL0_64", - - "SYNC_INVALID_EL0_32", - "IRQ_INVALID_EL0_32", - "FIQ_INVALID_EL0_32", - "ERROR_INVALID_EL0_32" -}; void enable_interrupt_controller() { REGS_IRQ->irq0_enable_0 = SYS_TIMER_IRQ_1 | SYS_TIMER_IRQ_3; @@ -31,14 +8,6 @@ void disable_interrupt_controller() { REGS_IRQ->irq0_enable_0 = 0; } -void show_invalid_entry_message(int type, unsigned long esr, unsigned long address) { - debugstr(entry_error_messages[type]); - debugstr(" ESR: "); - debughex(esr); - debugstr("Addr: "); - debughex(address); -} - void handle_irq() { unsigned int irq = REGS_IRQ->irq0_pending_0; diff --git a/part15-tcpip/kernel/irqentry.S b/part15-tcpip/kernel/irqentry.S index 28d0b94..d24ae00 100644 --- a/part15-tcpip/kernel/irqentry.S +++ b/part15-tcpip/kernel/irqentry.S @@ -67,7 +67,11 @@ mov x0, #\type mrs x1, esr_el1 mrs x2, elr_el1 - bl show_invalid_entry_message + + // We could pass this to a function to print an error here + // e.g. bl show_invalid_entry_message + // + // For now we'll just hang b err_hang .endm