/* Autor: Jose Velandia y Henry Lizaro. Curso: Dise�o Avanzado de Hardware Universidad Pontificia Bolivariana Semillero ADT FSM for MCP4821 */ module MCP4821(clk_40mhz, START, ENABLE, GAINx2, SHDN, TRAMA, CSn, SCK, SDI, LDAC, FINISH); input clk_40mhz; input START; input [11:0]TRAMA; input ENABLE; input GAINx2; input SHDN; output CSn; output SCK; output SDI; output LDAC; output FINISH; //PARA LOS PARAMETROS DE ESTADO VER DATASHEET.. TIEMPOS MINIMOS .. GUIARSE POR LA LINEA PUNTEADA ENCIMA DE LA OSCURA, YA QUE ES PARA ALTAS FREC. /////////////////////////////CSn SCK SDI_ON LDAC LDAC_ON_H LDAC_ON_L IDLE_ON NADA parameter ESTADO_1 = 8'b___1___1_____0_____1_______0________0__________0________0;///CSn EN ALTO Y SCK EN ALTO. parameter ESTADO_2 = 8'b___0___1_____0_____1_______0________0__________0________0;///CSn EN BAJO Y SCK EN BAJO. parameter ESTADO_3 = 8'b___0___0_____1_____1_______0________0__________0________0;///TRANSICION DE LOS 16 FLANCOS DE DATOS/// parameter ESTADO_4 = 8'b___0___1_____1_____1_______0________0__________0________0;///TRANSICION DE LOS 16 FLANCOS DE DATOS/// parameter ESTADO_5 = 8'b___1___1_____0_____1_______1________0__________0________0;///LDAC ALTO High parameter ESTADO_6 = 8'b___1___0_____0_____0_______0________1__________0________0;///LDAC BAJO Low parameter ESTADO_7 = 8'b___1___1_____0_____1_______0________0__________1________0;///TIEMPO IDLE OBLIGADO FINAL //======================================================= // REG/WIRE declarations //======================================================= //////ESTADO EXTRA QUE NO FUE NECESARIO AUNQUE PUEDE SERVIR PARA MONTAR UN INDICADOR DE INICIO O FINAL wire NADA; //////HABILITADORES DE CONTEOS////// wire SDI_ON; wire LDAC_ON_H; wire LDAC_ON_L; wire IDLE_ON; /////CONTEO DE SDI//// reg [4:0]SDI_CONT=4'd0; ////CONTEOS DE RETRASO///DEBIDO A QUE LDAC ES MUY CAPRICHOSO Y NECESITA UNOS TIEMPOS MINIMOS MAS ALTOS QUE LOS DEMAS reg [2:0]LDAC_CONT_H=3'd0; reg [2:0]LDAC_CONT_L=3'd0; reg [2:0]IDLE_CONT=3'd0; /////REGISTRO QUE CONTIENE E INDICA EL ESTADO EN EL QUE SE ENCUENTRA LA MAQUINA ACTUALMENTE//////// reg [7:0]STATE = ESTADO_1[7:0]; ///REGISTRO QUE TOMA UN MUESTREO DE LA TRAMA DE ENTRADA A ENVIAR///LA SE�AL DE ENTRADA ES MUY CAMBIANTE Y SE DEBE ASEGURAR UNA MUESTRA FIJA EN ESTE REGISTRO reg [15:0]TRAMA_REG = 15'd0; //======================================================= // Structural coding //======================================================= //SDI DEBE CONTENER LOS 16 BITS QUE CONTIENE LA TRAMA CADA QUE PASAN LOS FLANCOS DE SCK //ESTOS FLANCOS PUEDEN GENERAR UN CONTEO "SDI_CONT[4:0]" QUE AUTOMATICAMENTE ASIGNA A SDI EN EL BIT CORRECTO DE LA TRAMA //A MEDIDA QUE AUMENTA EL CONTEO DISMINUYE EL BIT POR ESO LA RESTA //LA SUMA DE UN "1" SE DA PORQUE EL PRIMER FLANCO DESCENDENTE DE SCK "LINEA PUNTEADA EN DATASHEET" PRODUCE UN CONTEO NO DESEADO EXTRA Y DE ESTA MANERA SE PUEDE CONTRARRESTAR EN INDICAR LA CORRECTA ASIGNACION DE SDI AL BIT CORRESPONDIENTE assign SDI = TRAMA_REG[(4'd15)-(SDI_CONT[4:0])+4'd1]; ////ASIGNACIONES DE LOS BITS DE ESTADO //// assign CSn = STATE[7];/////COMUNICACION SPI assign SCK = STATE[6];/////COMUNICACION SPI assign SDI_ON = STATE[5];/////HABILITADOR DE CONTEO SDI assign LDAC = STATE[4];/////COMUNICACION SPI assign LDAC_ON_H = STATE[3];/////RETRASO assign LDAC_ON_L = STATE[2];/////RETRASO assign IDLE_ON = STATE[1];/////RETRASO assign NADA = STATE[0];/////SIMPLEMTE UN EXTRA ///INDICA EL PASO POR EL ULTIMO ESTADO DEL SISTEMA QUE ES CUANDO SE HABILITA EL CONTEO FINAL DE TIEMPO IDLE OBLIGATORIO//// assign FINISH=IDLE_ON; ///AQUI SE VE COMO CADA FLANCO DE DESCENDENDTE DE LA SE�AL SCK AUMENTA "SDI_CONT" LO QUE AUTOMATICAMENTE VARIA EL BIT DE LA TRAMA QUE SE ASIGNA AL VERDADERO PIN SDI//// always@(negedge SCK) begin if(SDI_ON)///////////HABILITA EL CONTEO MIENTRAS SE ENCUENTREN PASANDO LOS 16 FLANCOS CORRESPONDIENTES AL ENVIO SERIAL "ESTADOS 3 Y 4" begin SDI_CONT[4:0]<=SDI_CONT[4:0] + 1'd1; end else begin SDI_CONT[4:0]<=4'd0;/////AL FINAL DEL DIAGRAMA DE TIEMPOS MINIMOS EN LA LINEA PUNTEADA NUEVAMENTE LA SE�AL "SCK" BAJA, PERO PARA ESE ENTONCES "SDI_ON" YA NO ESTA ACTIVO Y REINICIA EL CONTEO end end // // ///SE DEBE EVITAR QUE MIENTRAS SE ENVIE LA TRAMA ESTA ESTE CAMBIANDO ABRUPTAMENTE ASI QUE AQUI SE GUARDA UNA MUESTRA DE LA ENTRADA EN REGISTRO CON EL CUAL ESTA MAQUINA TRABAJA always@(posedge clk_40mhz) begin if(CSn) begin TRAMA_REG[15:0]<={~ENABLE,1'hx,~GAINx2,~SHDN,TRAMA[11:0]};/// CADA FLANCO DE RELOJ SE ESTA REGISTRANDO LA ENTRADA end else begin TRAMA_REG[15:0]<=TRAMA_REG[15:0];///CUANDO LA SE�AL CSn CAE A BAJO, INDICA QUE INICIARA EL ENVIO SERIAL Y POR TANTO YA NO SE REGISTRARA MAS EL VALOR DE LA ENTRADA HASTA QUE ESTA SE�AL VUELVA A SUBIR A ALTO Y LO PERMITA end end ////CONTEOS DE RETRASO//////CUANDO ACABAN LOS 16 FLANCOS DE "SCK" CORRESPONDIENTES AL ENVIO DE DATOS Y SUBE LA SE�AL CSn A ALTO, "ESTADOS 5, 6 Y 7" ////EXISTEN UNOS TIEMPOS MINIMOS EN DONDE LA SE�AL "LDAC" SE MANTIENDE ALTO LUEGO BAJO Y LUEGO ALTO NUEVAMENTE CON TODAS LAS SE�ALES DE CONTROL ALTAS(TIEMPO IDLE). always@(posedge clk_40mhz) begin //////LDAC_H//////AQUI SE REPRODUCE EL TIEMPO MINIMO EN EL CUAL LDAC SE MANTIENE ALTO ANTES DE CAER A BAJO if(LDAC_ON_H) begin LDAC_CONT_H[2:0]<=LDAC_CONT_H[2:0] + 1'd1; end else begin LDAC_CONT_H[2:0]=1'b0; end //////LDAC_L//////AQUI SE REPRODUCE EL TIEMPO MINIMO EN EL CUAL LDAC SE MANTIENE BAJO ANTES DE SUBIR A NIVEL ALTO if(LDAC_ON_L) begin LDAC_CONT_L[2:0]<=LDAC_CONT_L[2:0] + 1'd1; end else begin LDAC_CONT_L=1'b0; end //////IDLE//////AQUI SE REPRODUCE EL TIEMPO MINIMO EN DONDE AL FINAL TODAS LAS SE�ALES SE ECUENTRAN EN NIVEL ALTO ANTES QUE CSn CAIGA A BAJO E INICIE OTRO ENVIO SERIAL if(IDLE_ON) begin IDLE_CONT[2:0]<=IDLE_CONT[2:0] + 1'd1; end else begin IDLE_CONT[2:0]=3'b0; end end ///////GUIARSE SIEMPRE CON EL DATASHEET EN LA PARTE DE TIEMPOS MINIMOS Y ALTA FRECUENCIA(LINEA PUNTEADA). /////////TRANSICIONES DE ESTADO always@(posedge clk_40mhz) begin case(STATE[7:0]) ESTADO_1:begin if(START)///SI LA SE�AL START SE MANTIEN EN ALTO EL SISTEMA CORRERA SEGUIDAMENTE begin STATE[7:0]<=ESTADO_2[7:0]; end else begin STATE[7:0]<=ESTADO_1[7:0];////DE OTRO MODO QUEDARA EL SISTEMA QUEDARA INMERSO EN ESTE ESTADO end end ESTADO_2:begin STATE[7:0]<=ESTADO_3[7:0];///SE DEBE PASAR POR EL ESTADO 2 ANTES DE PASAR POR EL 3 PARA HACER CAER LA SE�AL DE CSn end ESTADO_3:begin////SE CARGA UN CONTEO SDI Y POR TANTO SDI EN UN VALOR QUE CORRESPONDE AL BIT A TRASMITIR DE LA TRAMA STATE[7:0]<=ESTADO_4[7:0];///SE DEBE PASAR POR EL ESTADO 3 ANTES DE PASAR POR EL 4 PARA HACER CAER LA SE�AL DE SCK end ESTADO_4:begin//// SE CARGA VALOR DE SDI AL DAC YA QUE EL ESTADO 4 GENERA QUE LA SE�AL "SCK" CAMBIE A ALTO AL VENIR DEL ESTADO 3 if(SDI_CONT<16) begin STATE[7:0]<=ESTADO_3[7:0];//SE VUELVE AL ESTADO 3 PARA HACER CAER LA SE�AL "SCK" MIENTRAS NO HAYAN PASADO LOS 16 FLANCOS DE ENVIO, ASI SE GENERA UN FLANCO DESCENDENTE QUE INCREMENTA UN CONTEO SDI Y AUTOMATICAMENTE LA SE�AL SDI QUEDA CON EL BIT INDICADO DE LA TRAMA end else begin STATE[7:0]<=ESTADO_5[7:0];//SI YA SE COMPLETAN LOS 16 BITS SE VA AL ESTADO 5 EN DONDE SUBE A ALTO LA SE�AL "SCK" end end ESTADO_5:begin if(LDAC_CONT_H[2:0]<1)///ANTES QUE CAIGA A BAJO LA SE�AL "LDAC" HAY QUE MANTENERLA UN TIEMPO MINIMO EN ALTO GRACIAS AL "LDAC_CONT_H", QUE SE HABILITA EN ESTE ESTADO GRACIAS A "LDAC_ON_H". begin STATE[7:0]<=ESTADO_5[7:0]; end else begin STATE[7:0]<=ESTADO_6[7:0];//LUEGO SI PUEDE IR AL ESTADO 6 Y CAER A NIVEL BAJO end end ESTADO_6:begin if(LDAC_CONT_L[2:0]<4)//AQUI SE MANTIENE EN BAJO LA SE�AL "LDAC" LO CORRESPONDIENTE A SU TIEMPO MINIMO PARA VOLVER A ESTAR EN ALTO EN EL ESTADO 7, GRACIAS AL CONTEO "LDAC_CONT_L", QUE SE HABILITA EN ESTE ESTADO GRACIAS A "LDAC_ON_L" begin STATE[7:0]<=ESTADO_6[7:0];//AQUI TAMBIEN CAE A NIVEL BAJO LA SE�AL "SCK" PROPUESTA EN LA LINEA PUNTEADA DEL DATASHEET end else begin STATE[7:0]<=ESTADO_7[7:0]; end end ESTADO_7:begin if(IDLE_CONT[2:0]<0)//AQUI SUBE A NIVEL ALTO LA SE�AL "SCK" PROPUESTA EN LA LINEA PUNTEADA DEL DATASHEET Y GRACIAS A "IDLE_CONT" EL SISTEMA CUMPLE CON SU TIEMPO MINIMO DE IDLE ANTES DE PERMITIR UN NUEVO ENVIO SERIAL GRACIAS AL HABILITADOR "IDLE_ON" ACTIVO EN ESTE ESTADO. begin STATE[7:0]<=ESTADO_7[7:0];//AQUI TAMBIEN SUBE LA SE�AL "LDAC" Y ESPERA NO MUCHO DADO QUE CUANDO EL SISTEMA VA AL ESTADO 1 ANTES DE IR A CUALQUIER OTRO ESTADO, EXISTE UN TIEMPO DE DEMORA EL CUAL HARIA PARTE DEL TIEMPO IDLE MINIMO QUE AQUI SE QUIERE REPRODUCIR ASI QUE PRACTICAMENTE SE PUEDE PASAR DIRECTAMENTE AL ESTADO 1. end else begin STATE[7:0]<=ESTADO_1[7:0];//YA ES POSIBLE IR AL ESTADO 1// SIEMPRE PASARA AUTOMATICAMENTE A ESTE ESTADO POR LO EXPLICADO EN EL COMENTARIO ANTERIOR, ESTE CONTEO SE HACE CON EL FIN DE QUE EL SISTEMA NO QUEDE AL BORDE DE SUS VALORES LIMITE, SI SE QUIERE LLEGAR A MODIFICAR SOLO SERIA CUESTION DE CAMBIARA LAS CONSTANTES DE CONDICION DE LOS CONTADORES A MAS GRANDES end end default: begin STATE[7:0]<=ESTADO_1[7:0];//COMO DEFAULT SI EL SISTEMA FALLA IRA AL ESTADO 1 end endcase end endmodule