mirror of
https://github.com/isometimes/rpi4-osdev
synced 2024-11-22 02:00:40 +00:00
Updated docs
This commit is contained in:
parent
dfc89a4449
commit
2f2b5df1fd
4 changed files with 41 additions and 33 deletions
|
@ -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!
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue