Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
/* Copyright (C) 2015 Kristian Sloth Lauszus. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Kristian Sloth Lauszus
Web : http://www.lauszus.com
e-mail : lauszus@gmail.com
*/
// Based on: https://github.com/diydrones/ardupilot/tree/5ddbcc296dd6dd9ac9ed6316ac3134c736ae8a78/libraries/AP_OpticalFlow
#include <stdint.h>
#include <stdbool.h>
#if USE_FLOW_SENSOR
#include "ADNS3080.h"
#include "Config.h"
#include "SPI.h"
#include "Time.h"
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#if UART_DEBUG
#include "utils/uartstdio.h" // Add "UART_BUFFERED" to preprocessor
#endif
// Register Map for the ADNS3080 Optical OpticalFlow Sensor
#define ADNS3080_PRODUCT_ID 0x00
#define ADNS3080_MOTION 0x02
#define ADNS3080_DELTA_X 0x03
#define ADNS3080_DELTA_Y 0x04
#define ADNS3080_SQUAL 0x05
#define ADNS3080_CONFIGURATION_BITS 0x0A
#define ADNS3080_MOTION_CLEAR 0x12
#define ADNS3080_FRAME_CAPTURE 0x13
#define ADNS3080_MOTION_BURST 0x50
// ADNS3080 hardware config
#define ADNS3080_PIXELS_X 30
#define ADNS3080_PIXELS_Y 30
// Id returned by ADNS3080_PRODUCT_ID register
#define ADNS3080_PRODUCT_ID_VALUE 0x17
// Registers should be bitwise OR with this value when writing
#define ADNS3080_WRITE_REG_VALUE 0x80
static void reset(void) {
GPIOPinWrite(GPIO_ADNS3080_RESET_BASE, GPIO_ADNS3080_RESET_PIN, GPIO_ADNS3080_RESET_PIN); // Set high
delayMicroseconds(10);
GPIOPinWrite(GPIO_ADNS3080_RESET_BASE, GPIO_ADNS3080_RESET_PIN, 0); // Set low
delayMicroseconds(500); // Wait for sensor to get ready
}
void initADNS3080(void) {
// Set reset pin as output
SysCtlPeripheralEnable(GPIO_ADNS3080_RESET_PERIPH); // Enable GPIO peripheral
SysCtlDelay(2); // Insert a few cycles after enabling the peripheral to allow the clock to be fully activated
GPIOPinTypeGPIOOutput(GPIO_ADNS3080_RESET_BASE, GPIO_ADNS3080_RESET_PIN); // Set as output
reset();
uint8_t id = spiRead(ADNS3080_PRODUCT_ID);
if (id == ADNS3080_PRODUCT_ID_VALUE) {
#if UART_DEBUG
UARTprintf("ADNS-3080 found\n");
#endif
} else {
#if UART_DEBUG
UARTprintf("Could not find ADNS-3080: %02X\n", id);
#endif
while (1);
}
uint8_t config = spiRead(ADNS3080_CONFIGURATION_BITS);
spiWrite(ADNS3080_CONFIGURATION_BITS | ADNS3080_WRITE_REG_VALUE, config | 0x10); // Set resolution to 1600 counts per inch
}
// Run: 'python ADNS3080ImageGrabber.py' in order to see the data
static void __attribute__((unused)) printPixelData(void) {
#if UART_DEBUG
bool isFirstPixel = true;
// Write to frame capture register to force capture of frame
spiWrite(ADNS3080_FRAME_CAPTURE | ADNS3080_WRITE_REG_VALUE, 0x83);
// Wait 3 frame periods + 10 nanoseconds for frame to be captured
delayMicroseconds(1510); // Minimum frame speed is 2000 frames/second so 1 frame = 500 nano seconds. So 500 x 3 + 10 = 1510
// Display the pixel data
for (uint8_t i = 0; i < ADNS3080_PIXELS_Y; i++) {
for (uint8_t j = 0; j < ADNS3080_PIXELS_X; j++) {
uint8_t regValue = spiRead(ADNS3080_FRAME_CAPTURE);
if (isFirstPixel && !(regValue & 0x40)) {
UARTprintf("Failed to find first pixel: %02X\n", regValue);
goto reset;
}
isFirstPixel = false;
char pixelValue = regValue << 2; // Only lower 6 bits contains data
UARTwrite(&pixelValue, 1); // Send pixels as raw bytes
}
UARTFlushTx(false);
}
reset:
reset(); // Hardware reset to restore sensor to normal operation
#endif
}
bool dataReadyADNS3080(void) {
return true;
}
void getADNS3080Data(int32_t __attribute__((unused)) *x, int32_t __attribute__((unused)) *y) {
#if 1
// Read sensor
uint8_t buf[4];
spiReadData(ADNS3080_MOTION_BURST, buf, 4);
uint8_t motion = buf[0];
//UARTprintf("%02X\n", motion & 0x01); // Resolution bit
if (motion & 0x10) { // Check if we've had an overflow
#if UART_DEBUG
UARTprintf("ADNS-3080 overflow\n");
#endif
} else if (motion & 0x80) {
int8_t dx = buf[1];
int8_t dy = buf[2];
uint8_t surfaceQuality = buf[3];
(void)surfaceQuality; // Suppress warning
*x += dx;
*y += dy;
#if 1 && UART_DEBUG
// Print values
UARTprintf("%d,%d\t%d,%d\t%u\n", *x, dx, *y, dy, surfaceQuality);
UARTFlushTx(false);
#endif
}
#if 0
else
UARTprintf("%02X\n", motion);
#endif
#else
UARTprintf("start\n");
printPixelData();
UARTFlushTx(false);
delay(250);
#endif
}
// Will cause the Delta_X, Delta_Y, and internal motion registers to be cleared
void clearMotion(int32_t *x, int32_t *y) {
spiWrite(ADNS3080_MOTION_CLEAR | ADNS3080_WRITE_REG_VALUE, 0xFF); // Writing anything to this register will clear the sensor's motion registers
*x = *y = 0;
}
#endif // USE_FLOW_SENSOR
c60021a68This file is pinned to the selected release. Download the original to open it in your design tool.