/* 2020-12-10 Michael Nowak http://www.mino-elektronik.de Alle Angaben ohne Gewaehr ! */ #define AS6501 #include "system_H750.h" uint32_t lese_stop_A(void); uint32_t lese_stop_B(void); #define REF_A_ADR 8 // Ergebnisse ab hier #define STOP_A_ADR 11 #define REF_B_ADR 20 #define STOP_B_ADR 23 #define OPC_POWER_ON 0x30 // power-on reset #define OPC_INIT 0x18 // init und start #define OPC_WRITE_CFG 0x80 // Konfiguration schreiben #define OPC_READ_CFG 0x40 // Konfiguration lesen #define OPC_READ_DATA 0x60 // Ergebnisse lesen ab inkl. Adresse #define MAX_INIT_TAB 17 uint32_t dummy; const uint8_t AS6501_init_tab[17] = { 0x15, // stop-A, stop-B und ext. REFCLK einschalten 0x85, // stop-A und stop-B auswerten, 1x Auswertung 0x00, // LVDS nicht aktiv (uint8_t)(REFCLK_AUFLOESUNG), // LSB (uint8_t)(REFCLK_AUFLOESUNG >> 8), // MSB-1 (uint8_t)(REFCLK_AUFLOESUNG >> 16), // MSB 0x00, // LVDS nicht aktiv 0x00, // dto. 0xa1, // interne Konstanten 0x13, 0x00, 0x0a, 0xcc, 0xcc, 0xf1, 0x7d, // bis hierhin 0x04 // CMOS-Pegel Eingänge }; // Befehl und Startadresse ausgeben void TDC_write(uint8_t cmd) { while(!(SPI1->SR & SPI_SR_TXP)); // freies FIFO abwarten *(__IO uint8_t *)&SPI1->TXDR = (uint8_t)(cmd); while(!(SPI1->SR & SPI_SR_TXC)); // Ausgabe abwarten } // RX-FIFO leeren void flush_SPI1(void) { while((SPI1->SR & (SPI_SR_RXWNE | SPI_SR_RXPLVL))) SPI1->RXDR; } // WERT holen uint8_t TDC_read(void) { uint8_t data; *(__IO uint8_t *)&SPI1->TXDR = 0; while(!(SPI1->SR & (SPI_SR_RXWNE | SPI_SR_RXPLVL))); data = *(__IO uint8_t *)&SPI1->RXDR; return(data); } int teste_REF10(void) { volatile uint32_t n; int temp, i, alt_port; RCC->AHB4ENR |= RCC_AHB4ENR_GPIOBEN; // Port aktivieren GPIOB->MODER &= ~(CLR_MODER << (REF10_AUSGANG * 2)); // B6 = Input GPIOB->PUPDR |= 1 << REF10_AUSGANG * 2; // Pullup dazu einschalten i = 0; alt_port = GPIOB->IDR; for(n=0; n < 1000; n++) { temp = GPIOB->IDR; if((temp ^ alt_port) & BIT(REF10_AUSGANG)) i++; alt_port = temp; } return(i); } void init_t4(void) { static uint32_t alter_takt; if(alter_takt != SystemTimerClock) { // geänderte Frequenz TIM4->CR1 = 0; // stoppen RCC->APB1LENR |= RCC_APB1LENR_TIM4EN; RCC->AHB4ENR |= RCC_AHB4ENR_GPIOBEN; // Port aktivieren GPIOB->MODER &= ~(CLR_MODER << (REF10_AUSGANG * 2));// MODER PB6 = 0 GPIOB->MODER |= (AF << (REF10_AUSGANG * 2)); // PB6 auf Compare-Ausgang GPIOB->OSPEEDR |= V_HIGH_SPEED << REF10_AUSGANG * 2; // mit steilen Flanken GPIOB->AFR[0] |= (AFR_TIM4 << (REF10_AUSGANG * 4)); // TIM4_CH1 OCOMP TIM4->CCER |= TIM_CCER_CC1E; // Compare Output Enable TIM4->CCMR1 |= TIM_CCMR1_OC1M_0 | TIM_CCMR1_OC1M_1; // toggeln bei jedem Überlauf alter_takt = SystemTimerClock; // TIM4->ARR = (SystemTimerClock/MHZ_FAKTOR/20)-1; // Teiler für 10 MHz TIM4->ARR = 14; // Teiler für 9,333 MHz } TIM4->CR1 = TIM_CR1_CEN | TIM_CR1_ARPE; // starten } uint32_t init_AS6501(void) { volatile int n; int AS6501_vorhanden = 1; // default AS6501 vorhanden RCC->AHB4ENR |= RCC_AHB4ENR_GPIOBEN | (RCC_AHB4ENR_GPIOCEN); // PortB+C aktivieren RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; // SPI1 aktivieren GPIOB->MODER &= ~(CLR_MODER << (TDC_DIN * 2) | CLR_MODER << (TDC_DOUT * 2) | CLR_MODER << (TDC_SCLK * 2) | CLR_MODER << (TDC_SSN * 2)); // auf Eingang GPIOB->MODER |= (AF << (TDC_DIN * 2) | AF << (TDC_DOUT * 2) | AF << (TDC_SCLK * 2) | OUT << (TDC_SSN * 2)); // normaler Ausgang // Geschwindigkeit GPIOB->OSPEEDR |= (V_HIGH_SPEED << (TDC_DIN * 2) | V_HIGH_SPEED << (TDC_DOUT * 2) | V_HIGH_SPEED << (TDC_SCLK * 2) | V_HIGH_SPEED << (TDC_SSN * 2)); GPIOB->AFR[0] |= (AFR_SPI1 << (TDC_DIN * 4) | // AF für SPI1 auf PortB AFR_SPI1 << (TDC_DOUT * 4) | AFR_SPI1 << (TDC_SCLK * 4)); // SPI1->CR2 = 1; // 1 übertragung SPI1->CFG1 = SPI_CFG1_MBR_1 | 7; // Taktteiler / 4 mit 8 bit SPI1->CFG2 = SPI_CFG2_AFCNTR | // PortB bits nur für SPI1 SPI_CFG2_CPHA | // clock def. auf '0', neg. Flanke aktiv SPI_CFG2_SSOE | // clock def. auf '0', neg. Flanke aktiv SPI_CFG2_SSM | // clock def. auf '0', neg. Flanke aktiv SPI_CFG2_MASTER; // SPI1->CR1 |= SPI_CR1_SPE; // SPI1 einschalten SPI1->CR1 |= SPI_CR1_CSTART; // SPI1 einschalten set_pin(GPIOB, TDC_SSN, 1); // Select auf '1' F_ref10 = hse_value; // default für ext. Takt /* if(teste_REF10() < 10) { init_t4(); // Referenz-Takt erzeugen F_ref10 = (double)SystemTimerClock; F_ref10 /= 2.0; F_ref10 /= (TIM4->ARR+1); // alternativ 9,3... MHz } */ for(n=0; n<1000; n++); GPIOC->MODER &= ~(CLR_MODER << (TDC_INTN * 2)); // auf Eingang GPIOC->PUPDR |= 1 << TDC_INTN * 2; // Pullup INTN einschalten // poer-on reset set_pin(GPIOB, TDC_SSN, 0); // Select auf '0' aktiv TDC_write(OPC_POWER_ON); // Power-on reset set_pin(GPIOB, TDC_SSN, 1); // Select auf '1' passiv // Konfiguration schreiben set_pin(GPIOB, TDC_SSN, 0); // Select auf '0' aktiv TDC_write(OPC_WRITE_CFG); // Konfiguration schreiben for(n = 0; n < MAX_INIT_TAB; n++) { TDC_write(AS6501_init_tab[n]); flush_SPI1(); } set_pin(GPIOB, TDC_SSN, 1); // Select auf '1' passiv // Konfiguration prüfen set_pin(GPIOB, TDC_SSN, 0); // Select auf '0' aktiv TDC_write(OPC_READ_CFG); // Konfiguration zurücklesen flush_SPI1(); for(n = 0; n < MAX_INIT_TAB; n++) { if(TDC_read() != AS6501_init_tab[n]) AS6501_vorhanden = 0; // fehler aufgetreten oder AS6501 fehlt } set_pin(GPIOB, TDC_SSN, 1); // Select auf '1' passiv // AS6501 starten if(AS6501_vorhanden) { set_pin(GPIOB, TDC_SSN, 0); // Select auf '0' aktiv TDC_write(OPC_INIT); // Power-on reset set_pin(GPIOB, TDC_SSN, 1); // Select auf '1' passiv } for(n=0; n<100000; n++); SPI1->CR1 &= ~SPI_CR1_SPE; // SPI1 abschalten SPI1->CFG1 = SPI_CFG1_MBR_0 | 7; // Taktteiler / 2 mit 8 bit SPI1->CR1 |= SPI_CR1_SPE; // SPI1 einschalten SPI1->CR1 |= SPI_CR1_CSTART; // SPI1 einschalten dummy = lese_stop_A(); dummy = lese_stop_B(); return(AS6501_vorhanden); } // 24 bit Ergebnisse holen uint32_t lese_ref_A(void) { uint32_t temp, n; set_pin(GPIOB, TDC_SSN, 0); // Select auf '0' aktiv SPI1->TXDR = (OPC_READ_DATA + REF_A_ADR); while(!(SPI1->SR & SPI_SR_TXC)); // vollständige Ausgabe abwarten set_pin(GPIOB, TDC_SSN, 1); // SSN wieder auf '1' for(n=0; n<4; n++) { temp <<= 8; temp |= *(__IO uint8_t *)&SPI1->RXDR; } return(temp & 0xffffff); } uint32_t lese_stop_A(void) { uint32_t temp, n; set_pin(GPIOB, TDC_SSN, 0); // Select auf '0' aktiv SPI1->TXDR = (OPC_READ_DATA + STOP_A_ADR); while(!(SPI1->SR & SPI_SR_TXC)); // vollständige Ausgabe abwarten set_pin(GPIOB, TDC_SSN, 1); // SSN wieder auf '1' for(n=0; n<4; n++) { temp <<= 8; temp |= *(__IO uint8_t *)&SPI1->RXDR; } return(temp & 0xffffff); } uint32_t lese_ref_B(void) { uint32_t temp, n; set_pin(GPIOB, TDC_SSN, 0); // Select auf '0' aktiv SPI1->TXDR = (OPC_READ_DATA + REF_B_ADR); while(!(SPI1->SR & SPI_SR_TXC)); // vollständige Ausgabe abwarten set_pin(GPIOB, TDC_SSN, 1); // SSN wieder auf '1' for(n=0; n<4; n++) { temp <<= 8; temp |= *(__IO uint8_t *)&SPI1->RXDR; } return(temp & 0xffffff); } uint32_t lese_stop_B(void) { uint32_t temp, n; set_pin(GPIOB, TDC_SSN, 0); // Select auf '0' aktiv SPI1->TXDR = (OPC_READ_DATA + STOP_B_ADR); while(!(SPI1->SR & SPI_SR_TXC)); // vollständige Ausgabe abwarten set_pin(GPIOB, TDC_SSN, 1); // SSN wieder auf '1' for(n=0; n<4; n++) { temp <<= 8; temp |= *(__IO uint8_t *)&SPI1->RXDR; } return(temp & 0xffffff); }