Project

General

Profile

Statistics
| Revision:

root / branches / encoders / code / projects / libdragonfly / spi.c @ 367

History | View | Annotate | Download (2.78 KB)

1
/* @file spi.c
2
 * @brief
3
 * SPI module
4
 * @bug broken
5
 */
6

    
7
#include <avr/interrupt.h>
8
#include "ring_buffer.h"
9
#include "spi.h"
10
#include <dragonfly_lib.h>
11

    
12

    
13
/*
14
SS = PB0
15
SCK = PB1
16
MOSI = PB2
17
MISO = PB3
18
*/
19
/* Controls clock freq. see Table 72 of specs*/
20

    
21
#define DOUBLE_SCK 1
22
#define SPR0_BIT 1
23
#define SPR1_BIT 0
24
#define LSB 1
25
#define MSB 0
26

    
27

    
28
RING_BUFFER_NEW(spi_buffer, 16, char, spi_send_buff, spi_rec_buff);
29
volatile char spi_status;
30
char spi_mode;
31
static spi_fun_recv_t  spi_recv_function;
32
//static spi_fun_send_t  spi_send_function;
33

    
34

    
35
void spi_init(char mode, spi_fun_recv_t recv_func) {
36
    usb_puts("spi_init: start\n");
37

    
38
        spi_mode = mode;
39

    
40
        //cli();
41
        RING_BUFFER_CLEAR(spi_send_buff);
42
        RING_BUFFER_CLEAR(spi_rec_buff);
43

    
44
        spi_recv_function = recv_func;
45
        //spi_send_function = send_func;
46

    
47
    /* Enables the SPI module
48
     * Enable Interrupt, Enable SPI Module, LSB First, Master Mode, Clock div = 64
49
     */
50
    SPCR = 0x00;
51
        SPCR = _BV(SPIE) | _BV(SPE) | _BV(DORD) | _BV(MSTR)| _BV(SPR1) | _BV(SPR0);
52
    SPSR = 0x00;
53
        SPSR = _BV(SPI2X); 
54
        
55
        spi_status = SPI_VOID;
56

    
57
    /* Set SCLK, SS, MOSI as outputs. MISO as input */
58
        if(mode == MASTER) {
59
            DDRB |= MOSI | SCLK | SS;
60
            DDRB &= ~MISO;
61
                PORTB |= SS;        //Keep SS High until transmit
62
        /* Set SCLK, SS, MOSI as inputs. MISO as output */
63
        } else {
64
            DDRB &= ~MOSI & ~SCLK & ~SS;
65
            DDRB |= MISO;
66
    }
67
        
68
        //sei();
69
        usb_puts("spi_init: end\n");
70
}
71

    
72
int spi_send(char *data, size_t bytes) {
73

    
74
        int i;
75
            
76
        usb_puts("spi_send: start\n");
77

    
78
    if(bytes == 0) 
79
        return -1; /* ...needed?*/
80
    
81
    //Prevent race condition on the buffer
82
    cli();
83
    for(i = 1; i < bytes; i++) {
84
        // Fail if the buffer is full
85
            if(RING_BUFFER_FULL(spi_send_buff)) {
86
                sei();
87
                return -1;
88
            }
89
        
90
            RING_BUFFER_ADD(spi_send_buff, data[i]);
91
    }
92
    
93
    sei();
94
    
95
    spi_status = SPI_SENDING;
96
        
97
        if (spi_mode == MASTER ){
98
                PORTB &= ~SS;        //Select slave
99
        }
100
    SPDR = *data;
101
        
102
        usb_puts("spi_send: end\n");
103
        //sei();
104
        
105
        return 1;
106
}
107

    
108
void spi_master_recv_on() {
109
        spi_status = SPI_VOID;
110
        PORTB &= ~SS;
111
}
112

    
113
void spi_master_recv_off() {
114
        spi_status = SPI_VOID;
115
        PORTB |= SS;
116
}
117

    
118
ISR(SIG_SPI) {
119
    usb_puts("ISR: start\n\r");
120
        char c;
121

    
122
        //usb_putc('['); usb_puti(c);usb_putc(',');usb_puti(spi_status);usb_puts("]\n\r");
123
        switch(spi_status){
124
                case SPI_SENDING:
125
                        if(!RING_BUFFER_EMPTY(spi_send_buff)) {
126
                                RING_BUFFER_REMOVE(spi_send_buff, c);
127
                                //usb_puts("SPDR=["); usb_puti(c);usb_putc(',');usb_puti(spi_status);usb_puts("]\n\r");
128
                                SPDR = c;
129
                                //c = SPDR;
130
                                //usb_puts("c=["); usb_puti(c);usb_putc(',');usb_puti(spi_status);usb_puts("]\n");
131
                                
132
                        } else {
133
                                if (spi_mode == MASTER)
134
                                        PORTB |= SS;                //Turn off Slave select
135
                                spi_status = SPI_VOID;
136
                        }
137
                        break;
138
                case SPI_VOID:
139
                        spi_recv_function(SPDR);
140
                        break;
141
        }
142

    
143
        usb_puts("ISR: end\n");
144
}