/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * wm8523.c * * Tue Jun 4 20:47:15 CEST 2013 * Copyright 2013 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of Pedal2Metal. * * Pedal2Metal is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Pedal2Metal is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Pedal2Metal; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "wm8523.h" #include #include #define WM8523_WRITE 0 #define WM8523_READ 1 static SPI_CFG_Type spi_cfg; static LPC_SPI_TypeDef spi; typedef struct __attribute__ ((packed)) { uint8_t rw:1; ///< See WM8523_WRITE and WM8523_READ uint8_t reg:7; ///< See page 35 in the WM8523 manual. uint16_t data; } WM8523_transfer_t; void WM8523_Init() { // 16 bit data tranfers spi_cfg.Databit = SPI_DATABIT_16; // WM8523 samples bits on rising edges. Mode 0 or 3 will work // http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase // Mode 0 spi_cfg.CPHA = SPI_CPHA_FIRST; // 0 spi_cfg.CPOL = SPI_CPOL_HI; // 0 /* // Mode 3 spi_cfg.CPHA = SPI_CPHA_SECOND; // 1 spi_cfg.CPOL = SPI_CPOL_LO; // 1 */ // We are the master spi_cfg.Mode = SPI_MASTER_MODE; // We run on a little endian mcu. spi_cfg.DataOrder = SPI_DATA_LSB_FIRST; // Se WM8523 manual page 14. Min clock pulse width 40ns ~= 25MHz spi_cfg.ClockRate = 1000000000; // 1MHz SPI_Init(&spi, &spi_cfg); } static volatile int spi_done = 0; void spi_mark_as_done() { spi_done = 1; } static void send(void *data, size_t size) { SPI_DATA_SETUP_Type dst; memset(&dst, 0, sizeof(dst)); dst.rx_data = data; dst.length = size; dst.callback = spi_mark_as_done; spi_done = 0; SPI_ReadWrite(&spi, &dst, SPI_TRANSFER_INTERRUPT); while(!spi_done) {} } static void receive(void *data, size_t size) { // http://anhnvnguyen.blogspot.dk/2010/04/lpc17xx-gpio-basic_05.html // TODO: set SSEL0 low // PINSEL3[13:12] = p1.21 (SSEL0) LPC_PINCON->PINSEL3 &= ~((1<<13)|(1<<12)); // set to 00 SPI_DATA_SETUP_Type dst; memset(&dst, 0, sizeof(dst)); dst.tx_data = data; dst.length = size; dst.callback = spi_mark_as_done; spi_done = 0; SPI_ReadWrite(&spi, &dst, SPI_TRANSFER_INTERRUPT); while(!spi_done) {} // TODO: set SSEL0 high } /** Volume update registers R06h and R07h are unavailable in SPI control mode. To use volume update in software control mode, I2C mode must be used. */ void WM8523_Configure() { WM8523_transfer_t transfer; transfer.rw = WM8523_READ; transfer.reg = 0; // R0 read version : 0x8523 transfer.data = 0; //send(&transfer, sizeof(transfer)); receive(&transfer, sizeof(transfer)); }