Updated docs

This commit is contained in:
Adam Greenwood-Byrne 2021-11-07 19:53:58 +00:00
parent dfc89a4449
commit 2f2b5df1fd
4 changed files with 41 additions and 33 deletions

View file

@ -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. 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. 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!

View file

@ -2,5 +2,4 @@ void spi_init();
void spi_send_recv(unsigned char *sbuffer, unsigned char *rbuffer, unsigned int size); void spi_send_recv(unsigned char *sbuffer, unsigned char *rbuffer, unsigned int size);
void spi_send(unsigned char *data, unsigned int size); void spi_send(unsigned char *data, unsigned int size);
void spi_recv(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); void spi_chip_select(unsigned char chip_select);

View file

@ -1,27 +1,4 @@
#include "kernel.h" #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() { void enable_interrupt_controller() {
REGS_IRQ->irq0_enable_0 = SYS_TIMER_IRQ_1 | SYS_TIMER_IRQ_3; 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; 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() { void handle_irq() {
unsigned int irq = REGS_IRQ->irq0_pending_0; unsigned int irq = REGS_IRQ->irq0_pending_0;

View file

@ -67,7 +67,11 @@
mov x0, #\type mov x0, #\type
mrs x1, esr_el1 mrs x1, esr_el1
mrs x2, elr_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 b err_hang
.endm .endm